Kotlin特色的设计模式

一、单例模式

1.饿汉式

类加载时就初始化,会提前占用内存。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化

  • Java

public class Singleton {

    private static Singleton S = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return S;
    }
}

  • Kotlin
object Singleton {
}

Kotlin是如何用一行代码实现单例的呢?我们来看看反编译后的java代码:
tools--Kotlin--show Kotlin Bytecode

public final class Singleton {
   public static final Singleton INSTANCE;

   private Singleton() {
   }

   static {
      Singleton var0 = new Singleton();
      INSTANCE = var0;
   }
}

可以看到,object修饰的类实际上就是Java里的静态单例,而静态代码是随着类加载的,只会加载一次,这样就实现了饿汉式单例

2. 懒汉式

  • Java
public class Singleton{
   private static Singleton S;
   private Singleton(){
   
   }
   public static getInstance(){
     if(S==null){
        S = new Singleton();
     }
     return S;
   }
   
}

  • Kotlin
class Singleton private constructor() {
    companion object {
        val S: Singleton by lazy { Singleton() }
    }
}

注:by lazy { ... }的初始化默认是线程安全的,并且能保证by lazy { ... }代码块中的代码最多被调用一次,我们深入源码看一下,lazy修饰符是如何实现懒加载和线程安全的,关键方法是SynchronizedLazyImpl(initializer):

image.png

private class SynchronizedLazyImpl(initializer: () -> T, lock: Any? = null) : Lazy, Serializable {
    private var initializer: (() -> T)? = initializer
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    // final field is required to enable safe publication of constructed instance
    private val lock = lock ?: this

    override val value: T
        get() { //此处判断_value已被初始化,则直接返回
            val _v1 = _value
            if (_v1 !== UNINITIALIZED_VALUE) {
                @Suppress("UNCHECKED_CAST")
                return _v1 as T
            }

            return synchronized(lock) {//增加线程同步锁,防止并发访问
                val _v2 = _value
                if (_v2 !== UNINITIALIZED_VALUE) {
                    @Suppress("UNCHECKED_CAST") (_v2 as T)
                } else {//未初始化时,真正实现初始化的代码
                    val typedValue = initializer!!()
                    _value = typedValue
                    initializer = null
                    typedValue
                }
            }
        }

    override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE

    override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."

    private fun writeReplace(): Any = InitializedLazyImpl(value)
}

二、建造者模式

主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。下面以我们常用的Dialog举例:

  • Java
public class Dialog {
    private String left;
    private String right;
    private String title;


    static class Builder {
        private String left;
        private String right;
        private String title;

        Builder left(String left) {
            this.left = left;
            return this;
        }

        Builder right(String right){
            this.right = right;
            return this;
        }

        Builder title(String title){
            this.title = title;
            return this;
        }

        Dialog build(){
            Dialog dialog = new Dialog();
            dialog.left = this.left;
            dialog.right = this.right;
            dialog.title = this.title;
            return dialog;
        }


    }
}

class DialogTest{

    void test(){
        Dialog dialog = new Dialog.Builder().left("left").right("right").title("titlle").build();
    }
}

  • Kotlin
class Dialog{
    var left:String =""
    var right:String=""
    var title:String ="title"
}



class DialogTest{
    @Test
    fun test(){
        val dialog = Dialog().apply {
            left = "left"
            right = "right"
            title = "title"
        }
    }
}

关键方法在于apply函数,它使得代码块能够在当前对象语境下,访问其非私有属性和函数,执行完毕后返回当前对象:

/**
 * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
 *
 * For detailed usage information see the documentation for [scope functions](https://kotlinlang.org/docs/reference/scope-functions.html#apply).
 */
@kotlin.internal.InlineOnly
public inline fun  T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

三、观察者模式

  • Java

观察者

public interface Observer {
     void update(Object object);
}

被观察者

public abstract class Observable {
    List observers = new ArrayList<>();

    public void register(Observer observer){
        this.observers.add(observer);
    }

    public void unRegister(Observer observer){
        this.observers.remove(observer);
    }

    public void notifyAllObservers(Object object){
        for (Observer observer : observers) {
            observer.update(object);
        }
    }
}

  • Kotlin
interface TextChangedListener {
    fun onTextChanged(newText: String)
}

class TextView {
    var listener: TextChangedListener? = null
    var text: String by Delegates.observable("") { prop, old, new ->
        listener?.onTextChanged(new)
    }
}

为了弄清楚如何实现的,我们查看下Delegates.observable的源码:

/**
     * Returns a property delegate for a read/write property that calls a specified callback function when changed.
     * @param initialValue the initial value of the property.
     * @param onChange the callback which is called after the change of the property is made. The value of the property
     *  has already been changed when this callback is invoked.
     *
     *  @sample samples.properties.Delegates.observableDelegate
     */
    public inline fun  observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
            ReadWriteProperty =
        object : ObservableProperty(initialValue) {
            override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
        }

是不是还没有看懂,我们只需要关注ObervableProperty这个类就行了,这里值的改变实际上代理给了ObervableProperty


/**
 * Implements the core logic of a property delegate for a read/write property that calls callback functions when changed.
 * @param initialValue the initial value of the property.
 */
public abstract class ObservableProperty(initialValue: T) : ReadWriteProperty {
    private var value = initialValue

    /**
     *  The callback which is called before a change to the property value is attempted.
     *  The value of the property hasn't been changed yet, when this callback is invoked.
     *  If the callback returns `true` the value of the property is being set to the new value,
     *  and if the callback returns `false` the new value is discarded and the property remains its old value.
     */
    protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true

    /**
     * The callback which is called after the change of the property is made. The value of the property
     * has already been changed when this callback is invoked.
     */
    protected open fun afterChange(property: KProperty<*>, oldValue: T, newValue: T): Unit {}

    public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value
    }

    public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val oldValue = this.value
        if (!beforeChange(property, oldValue, value)) {
            return
        }
        this.value = value
        afterChange(property, oldValue, value)
    }
}

ReadWriteProperty是一个什么东西呢?它在代理模式中用得非常多:

public interface ReadWriteProperty {
    /**
     * Returns the value of the property for the given object.
     * @param thisRef the object for which the value is requested.
     * @param property the metadata for the property.
     * @return the property value.
     */
    public operator fun getValue(thisRef: R, property: KProperty<*>): T

    /**
     * Sets the value of the property for the given object.
     * @param thisRef the object for which the value is requested.
     * @param property the metadata for the property.
     * @param value the value to set.
     */
    public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

当一个值被ReadWritPropery代理时,调用或者赋值都会相应地回调getValue和setValue方法

我们继续回ObservableProperty,到从命名就可以看出来,其是一个被观察者,当它的值发生改变时,会回调afterChange方法,最终会传递给我们自定义的onChange方法中,实现值的变化监听,这样就实现了最简单的观察者模式

四、代理模式

在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。下面举一个经纪人代理明星的例子:

interface People {
    fun speak()
}
class Broker :People{
    override fun speak() {
        print("hello")
    }
}
class Star(private val broker: Broker) :People by broker

class Test{
    @Test
    fun test(){
        val broker = Broker()
        val star = Star(broker)
        star.speak()
    }
}

在Koltin中实现代理模式非常简单,只需要试用by关键字就行了,上面的Star就是通过 传入的broker实现的代理,我们看到它自身是没有实现People类的抽象方法的,最终在test()中调用的实际上是其代理对象broker的speak,在Kotlin中by关键字主要有如下几点作用:

  • 类的代理 class
  • 属性延迟加载 lazy
  • 监听属性变化 Delegates.observable ( 扩展 Delegates.vetoable )
  • 自定义监听属性变化 ReadWriteProperty

我们再举个栗子,看看其如何实现属性的代理,和上面讲过的观察者模式有些类似

class Delegate {
    // 运算符重载
    operator fun getValue(thisRef: Any?, prop: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${prop.name}' to me!"
    }

    operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) {
        println("$value has been assigned to ${prop.name} in $thisRef")
    }

}

class Example {
    var d: String by Delegate()

    @Test
    fun test(){

        d = "d value"
        println("$d")

    }
}

运行结果是这样的:


image.png

从结果看,String类型的d的取值和赋值已经交给了Delegate类去实现,想不想知道如何实现的?我们来反编译下看看源码吧

public final class Delegate {
   @NotNull
   public final String getValue(@Nullable Object thisRef, @NotNull KProperty prop) {
      Intrinsics.checkParameterIsNotNull(prop, "prop");
      return thisRef + ", thank you for delegating '" + prop.getName() + "' to me!";
   }

   public final void setValue(@Nullable Object thisRef, @NotNull KProperty prop, @NotNull String value) {
      Intrinsics.checkParameterIsNotNull(prop, "prop");
      Intrinsics.checkParameterIsNotNull(value, "value");
      String var4 = value + " has been assigned to " + prop.getName() + " in " + thisRef;
      boolean var5 = false;
      System.out.println(var4);
   }
}


public final class Example {
   // $FF: synthetic field
   static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Example.class), "d", "getD()Ljava/lang/String;"))};
   @NotNull
   private final Delegate d$delegate = new Delegate();

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

   public final void setD(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "");
      this.d$delegate.setValue(this, $$delegatedProperties[0], var1);
   }

   @Test
   public final void test() {
      this.setD("d value");
      String var1 = String.valueOf(this.getD());
      boolean var2 = false;
      System.out.println(var1);
   }
}

可以看到,Example中给d取值和赋值实际上调用的是getD和setD方法,而且最终转而被Delegate对象代理,调用的是它的getValue和setValue方法,这个其实就是代理模式中by关键字的作用

你可能感兴趣的:(Kotlin特色的设计模式)