1. Object proxy.

The following is a proxy usage class

interface Base {
    fun print(a)
}

class BaseImpl(val x: Int) : Base {
    override fun print(a) { print(x) }
}

class Derived(b: Base) : Base by b

fun main(a){
    val b = BaseImpl(10)
    Derived(b).print()
}
Copy the code

Let’s convert kt code to Java code. The relevant annotation information is removed.

public interface Base {
   void print(a);
}

public final class BaseImpl implements Base {
   private final int x;

   public void print(a) {
      int var1 = this.x;
      boolean var2 = false;
      System.out.print(var1);
   }

   public final int getX(a) {
      return this.x;
   }

   public BaseImpl(int x) {
      this.x = x; }}public final class Derived implements Base {
   private final Base $$delegate_0;
   public Derived(@NotNull Base b) {
      Intrinsics.checkNotNullParameter(b, "b");
      super(a);this.$$delegate_0 = b;
   }
   public void print(a) {
      this.$$delegate_0.print(); }}public final class BaseKt {
   public static void main(String[] var0) {
      main();
   }
   public static final void main(a) {
      BaseImpl b = new BaseImpl(10);
      (newDerived((Base)b)).print(); }}Copy the code

You can see the corresponding Java code as follows

  1. First, Derived holds the direct implementation of the Base interface, $$Delegate_0.
  2. The compiler implements the Base interface for Derived, overrides the interface methods, and passes them to the $$Delegate_0 object.

So Derived has the capability of an interface, and it works the same way we wrote static proxy methods. Kotlin hides this implementation by using the by keyword.

Delegates greatly enhance the expressiveness of a class, and using the BY keyword can enhance the functionality of a class as long as you know the interface and how that interface is implemented.

2. Property proxy

import kotlin.reflect.KProperty
class Example {
    var p: String by Delegate(a)
}
class Delegate {
    operator fun getValue(thisRef: Any? , property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }

    operator fun setValue(thisRef: Any? , property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")}}fun main(a){
    print(Example().p)
}
Copy the code

Where thisRef is the class object, property can get information about the proxy property.

Here is the code to convert to Java.

public final class Delegate {
   @NotNull
   public final String getValue(@Nullable Object thisRef, @NotNull KProperty property) {
      Intrinsics.checkNotNullParameter(property, "property");
      return thisRef + ", thank you for delegating '" + property.getName() + "' to me!";
   }
   public final void setValue(@Nullable Object thisRef, @NotNull KProperty property, @NotNull String value) {
      Intrinsics.checkNotNullParameter(property, "property");
      Intrinsics.checkNotNullParameter(value, "value");
      String var4 = value + " has been assigned to '" + property.getName() + "' in " + thisRef + '. ';
      boolean var5 = false; System.out.println(var4); }}public final class Example {
   static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Example.class, "p"."getP()Ljava/lang/String;".0))};
   @NotNull
   private final Delegate p$delegate = new Delegate();

   @NotNull
   public final String getP(a) {
      return this.p$delegate.getValue(this, $$delegatedProperties[0]);
   }

   public final void setP(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "
      
       "
      ?>);
      this.p$delegate.setValue(this, $$delegatedProperties[0], var1); }}public final class ExampleKt {
   public static final void main(a) {
      String var0 = (new Example()).getP();
      boolean var1 = false;
      System.out.print(var0);
   }
   public static void main(String[] var0) { main(); }}Copy the code

You can see that compiled Java does a few things

  1. Generate a property delegate object p$delegate (delegate) and save it for later.
  2. Added getP() and setP() methods for property P, while the getP() and setP() methods are forwarded to P $delegate’s setValue()\getValue() method.

In addition, the property p is placed in a KPropery[] array, which can be passed to a P $delegate as a proxy to fetch information about P.

Attribute proxy enrichis the representation of class attributes, which can be enhanced and modified by proxy.

The whole idea of agency:

Holds the proxied object and forwards data to the proxied object when calling properties or methods. Delegation is a layer of transformation at the syntactic level.

The class proxy (delegate) does the following at compile time

  • The Base and BaseImpl of the interface remain unchanged
  • The proxyed class implements the Base proxy interface, overrides the interface method, and calls the corresponding method of the interface implementer (BaseImpl) in the interface method. The interface implementor (BaseImpl) takes over the Base method in the Derived class.

This is essentially a static proxy.

The property broker (property delegate) does the following at compile time

  • A Delegate object must have a set/get method, unchanged during compilation.
  • Add a Delegate object to the class (Example) that uses the property proxy. Generate getP() and setP() methods for attributes delegated to P. The actual getXX() and setXX() methods are forwarded to the Delegate’s setValue()\getValue(). Let the agent take over XX

Property gets and resets.

Proxies greatly enhance the expressiveness of classes and properties, allow lightweight extension and modification, and are more flexible and easier to use than inheritance.