美文网首页
Kotlin特色的设计模式

Kotlin特色的设计模式

作者: 刺客的幻影 | 来源:发表于2019-11-30 14:36 被阅读0次

    一、单例模式

    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<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, 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> 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<Observer> 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 <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
                ReadWriteProperty<Any?, T> =
            object : ObservableProperty<T>(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<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
        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<in R, T> {
        /**
         * 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, "<set-?>");
          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特色的设计模式

          本文链接:https://www.haomeiwen.com/subject/qvhtwctx.html