委托

先導(dǎo)知識(shí)

?我們所說的委托,其實(shí)就是一種設(shè)計(jì)模式:有兩個(gè)對(duì)象參與處理同一個(gè)請(qǐng)求,接受請(qǐng)求的對(duì)象將請(qǐng)求委托給另一個(gè)對(duì)象來處理。換一種方法來說就是,我們(調(diào)用方)操作的對(duì)象不會(huì)自己去處理邏輯,而會(huì)把工作委托給另外一個(gè)輔助對(duì)象去處理。委托模式使得我們可以使用聚合來替代繼承,更加靈活。舉個(gè)簡(jiǎn)單的例子,朋友圈的微商賣貨就是一種委托模式,“微商”代替廠家賣貨,廠家“委托”他們進(jìn)行銷售。在這種關(guān)系里,“微商”就相當(dāng)于“代理類”,而廠家則是“委托類”。

?Java在語法層面上是沒有支持委托模式的,但是可以通過代理模式來實(shí)現(xiàn)委托。Java的代理模式分為靜態(tài)代理和動(dòng)態(tài)代理,我們簡(jiǎn)單過一下。

靜態(tài)代理

?所謂靜態(tài)代理,是指代理類在編譯時(shí)就已經(jīng)創(chuàng)建好了。

public class ProxyDemo {

    public static void main(String[] args) {
        BaseImp imp = new BaseImp();
        Proxy proxy = new Proxy(imp);
        proxy.doSomething();
    }
}

interface Base {
    void doSomething();
}

//委托類
class BaseImp implements Base {

    @Override
    public void doSomething() {
        System.out.println("BaseImp do something...");
    }
}

//代理類
class Proxy implements Base {
    private final Base baseImp;

    public Proxy(Base base) {
        this.baseImp = base;
    }

    @Override
    public void doSomething() {
        baseImp.doSomething();
    }
}

?在這里,Proxy就是代理類,BaseImp則是委托類。當(dāng)我們調(diào)用Proxy的方法時(shí)執(zhí)行邏輯時(shí),Proxy就會(huì)去調(diào)用BaseImp實(shí)例來處理。在靜態(tài)代理中,代理類和委托類擁有共同的父類或者父接口。這里要提一嘴的是,關(guān)于兩個(gè)類的叫法問題。我們調(diào)用Proxy類,而Proxy再去調(diào)用(這里我理解為委托)BaseImp去做,而BaseImp卻叫做委托類,感覺是不是有點(diǎn)怪怪的(我覺得應(yīng)該叫被委托類更合適)。所以這時(shí)候我們可以反過來想,就是因?yàn)锽aseImp去委托了Proxy來代理它的事務(wù),所以它理所當(dāng)然就是委托方啦。當(dāng)然了,這里我們不用去糾結(jié),概念本身創(chuàng)造出來就是幫助我們來理解的,而不是讓我們鉆牛角尖的,所以我們清楚這個(gè)模式所要表達(dá)(傳遞)的意思就行。

?既然靜態(tài)代理在編譯時(shí)就產(chǎn)生對(duì)應(yīng)的字節(jié)碼文件,那也就意味著效率會(huì)比較高。但也是因此靜態(tài)代理只能為一個(gè)目標(biāo)對(duì)象服務(wù),如果目標(biāo)對(duì)象過多,就會(huì)對(duì)象產(chǎn)生較多的代理類。

動(dòng)態(tài)代理

?跟靜態(tài)代理不同的是,動(dòng)態(tài)代理的代理類是在運(yùn)行時(shí)生成的,我們看名字也看得出來。也就是說,動(dòng)態(tài)代理類是在程序運(yùn)行時(shí)由Java反射機(jī)制動(dòng)態(tài)生成的,我們不需要去編寫代理類的邏輯代碼。

?實(shí)現(xiàn)動(dòng)態(tài)代理的步驟為:
(1)定義公共接口及實(shí)現(xiàn)委托類。
(2)實(shí)現(xiàn)Java反射包的InvocationHandler接口,來創(chuàng)建代理類的調(diào)用處理器。
(3)動(dòng)態(tài)生成代理對(duì)象。
(4)通過代理對(duì)象調(diào)用方法。

public class DynamicProxyDemo {

    public static void main(String[] args) {
        BaseDynamicImpl dynamicImpl = new BaseDynamicImpl();
        //通過委托類來構(gòu)造調(diào)用處理器
        ProxyHandler proxyHandler = new ProxyHandler(dynamicImpl);
        //通過Java反射包的Proxy類來動(dòng)態(tài)生成代理對(duì)象
        BaseDynamic proxy = (BaseDynamic) Proxy.newProxyInstance(
                BaseDynamicImpl.class.getClassLoader(),
                BaseDynamicImpl.class.getInterfaces(),
                proxyHandler);
        //通過代理對(duì)象調(diào)用方法
        proxy.doSomething();
    }
}

//公共接口
interface BaseDynamic {
    void doSomething();
}

//委托類
class BaseDynamicImpl implements BaseDynamic {

    @Override
    public void doSomething() {
        System.out.println("BaseDynamicImpl do something...");
    }
}

//代理類的調(diào)用處理器
class ProxyHandler implements InvocationHandler {
    //一樣,我們需要持有共同的父類接口
    private final BaseDynamic baseDynamic;

    public ProxyHandler(BaseDynamic baseDynamic) {
        this.baseDynamic = baseDynamic;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        return method.invoke(baseDynamic, objects);
    }
}

?動(dòng)態(tài)代理涉及到兩個(gè)重要的Java API:
(1)java.lang.reflect.InvocationHandler:調(diào)用處理器接口,它的invoke方法用于集中處理在動(dòng)態(tài)代理類對(duì)象上的方法調(diào)用,通常在該方法中實(shí)現(xiàn)對(duì)委托類的代理訪問。
(2)java.lang.reflect.Proxy:Java動(dòng)態(tài)代理機(jī)制生成的所有動(dòng)態(tài)代理類的父類,提供了一組靜態(tài)方法來為一組接口動(dòng)態(tài)地生成代理類及其對(duì)象。

?很明顯,既然通過了反射代理方法,那么也就會(huì)意味著性能問題。但相應(yīng)的,動(dòng)態(tài)代理的優(yōu)勢(shì)也很明顯,可以顯著地減少代理類的數(shù)量,我們不需要每次都去為目標(biāo)對(duì)象創(chuàng)建相應(yīng)的代理類,使用起來更加靈活。Retrofit就是通過動(dòng)態(tài)代理對(duì)上層接口的封裝,讓我們可以用更加面向?qū)ο蟮倪壿?,輕松地訪進(jìn)行網(wǎng)絡(luò)操作。

Kotlin的委托模式

?說完了Java的委托,我們?cè)倩剡^頭來看看Kotlin的委托。

?作為極具創(chuàng)新的現(xiàn)代化語音,Kotlin直接在語法層面上支持了委托模式,那就意味著我們使用起來更加的方便了。Kotlin的委托分為類委托和委托屬性。

類委托

?我們還是用剛剛的例子:

interface Base {
    fun doSomething()
}

//委托類
class BaseImpl : Base {
    override fun doSomething() {
        println("BaseImpl do something...")
    }
}

//通過by關(guān)鍵字完成委托,Derived相當(dāng)于代理類
class Derived(base: Base) : Base by base

fun main(args: Array<String>) {
    val base = BaseImpl()
    val derived = Derived(base)
    derived.doSomething()
}

?你會(huì)發(fā)現(xiàn),非常簡(jiǎn)單,我們僅僅通過by關(guān)鍵字,便將職責(zé)委托給了BaseImpl類,當(dāng)然我們自己也要實(shí)現(xiàn)Base接口,才能實(shí)現(xiàn)相對(duì)應(yīng)方法的委托。其實(shí)我們寫的時(shí)候也可以發(fā)現(xiàn),當(dāng)我們只寫到繼承Base接口還沒寫by的時(shí)候,IDE是會(huì)報(bào)錯(cuò)的,提示你沒有去重寫對(duì)應(yīng)的方法。但當(dāng)我們通過by關(guān)鍵字實(shí)現(xiàn)委托之后,IDE就正常了。而這么做的好處我們剛剛也說過了,通過委托來替代繼承是一個(gè)很好的選擇,而Kotlin又給予了我們語法層面的支持,簡(jiǎn)直不要太爽!

?比如我們要實(shí)現(xiàn)一個(gè)Set類,但是大部分邏輯都跟HashSet差不多,這個(gè)時(shí)候我們就可以利用委托來實(shí)現(xiàn)。我們只需要重寫自己需要的方法即可:

class MySet<T>(private val helperSet: HashSet<T>) : Set<T> by helperSet {

    fun helloWorld() = println("Hello Kotlin World")

    override fun isEmpty(): Boolean {
        return false
    }
}

?同樣,我們通過by把邏輯委托給了helperSet,除了我們自己重寫的isEmpty()方法,當(dāng)然這里沒有實(shí)際意義,只是為了演示,然后我們又添加了一個(gè)自己獨(dú)有的helloWorld()方法。這樣一來,我們就擁有了HashSet的全部能力以及我們自己獨(dú)有的方法,一個(gè)全新的數(shù)據(jù)結(jié)構(gòu)類就誕生了。

?既然by這么神奇,我們就來看看它背后是怎么實(shí)現(xiàn)的。我們先把文件編譯成Kotlin字節(jié)碼,再反編譯回來:

public final class MySet implements Set, KMappedMarker {
   private final HashSet helperSet;

   public final void helloWorld() {
      String var1 = "Hello Kotlin World";
      System.out.println(var1);
   }

   public boolean isEmpty() {
      return false;
   }

   public MySet(@NotNull HashSet helperSet) {
      Intrinsics.checkNotNullParameter(helperSet, "helperSet");
      super();
      this.helperSet = helperSet;
   }

//省略其他方法...
}

?你會(huì)發(fā)現(xiàn),和我們剛剛Java的靜態(tài)代理一模一樣,只不過是Kotlin幫我們默默地把事情都做了(它真的,我哭死)。

委托屬性

?類委托的核心思想是將一個(gè)類的具體實(shí)現(xiàn)委托給另外一個(gè)類去完成,而委托屬性的核心思想是將一個(gè)屬性(字段)的具體實(shí)現(xiàn)委托給另外一個(gè)類去完成。先看下委托屬性的語法結(jié)構(gòu):

class PropertyProxy {
    var p by Delegate()
}

?同樣的,通過by關(guān)鍵字來實(shí)現(xiàn),這意味著將p屬性的具體實(shí)現(xiàn)委托給Delegate類來完成。當(dāng)然這個(gè)時(shí)候,IDE會(huì)報(bào)錯(cuò),提示我們創(chuàng)建帶有g(shù)etValue和setValue方法的Delegate類,根據(jù)提示去創(chuàng)建這兩個(gè)方法即可,我們來具體實(shí)現(xiàn)一下:

class Delegate {

    var propertyValue: Any? = null

    operator fun getValue(proxy: PropertyProxy, property: KProperty<*>): Any? {
        return propertyValue
    }

    operator fun setValue(proxy: PropertyProxy, property: KProperty<*>, any: Any?) {
        propertyValue = any
    }

}

?可以看到,我們重寫了getValue()和setValue()方法,并用operator關(guān)鍵字進(jìn)行聲明。我們直接看setValue()方法,第一個(gè)參數(shù)就是我們的代理類,也就是聲明該類(Delegate)的委托功能可以在哪個(gè)類中使用;第二個(gè)參數(shù)KProperty< * >是Kotlin的一個(gè)屬性操作類,可用于獲取各種屬性相關(guān)的值,當(dāng)前場(chǎng)景下用不上,而< * >表示我們不關(guān)心泛型的具體類型,類似于Java中的<?>。

?委托屬性的工作流程就是當(dāng)我們?nèi)ソoPropertyProxy類的p屬性賦值的時(shí)候,就會(huì)調(diào)用Delegate類的setValue方法,而當(dāng)我們獲取p屬性的值時(shí),就會(huì)去調(diào)用Delegate類的getValue方法。就是這么簡(jiǎn)單,真正的難點(diǎn)在于如何靈活應(yīng)用。

by lazy

?既然談到委托屬性,那總是繞不開by lazy的。相信大家也很熟悉,平常幾乎都用得飛起。by lazy其實(shí)是屬于延遲屬性,我們經(jīng)常用的lateinit也是(具體來說是通過它們來修飾),而延遲屬性就是委托屬性的一種。

?說回by lazy,其中l(wèi)azy并不是關(guān)鍵字,而是一個(gè)高階函數(shù),可以接收一個(gè)lambda表達(dá)式作為參數(shù),我們來看下面的例子:

class PropertyProxy {
    var p by Delegate()

    val str: String by lazy {
        println("enter lazy()")
        "Value"
    }
}

fun main(args: Array<String>) {
    val proxy = PropertyProxy()
    println(proxy.str)
    println("------")
    println(proxy.str)
}

?新增一個(gè)str屬性,然后我們調(diào)用它,把結(jié)果打印出來:

enter lazy()
Value
------
Value

?我們會(huì)發(fā)現(xiàn),調(diào)用了兩次str屬性,而"enter lazy()"只打印了一次。這是因?yàn)閘azy函數(shù)只有在第一次調(diào)用時(shí)執(zhí)行整個(gè)Lambda表達(dá)式,而后調(diào)用則會(huì)直接返回第一次調(diào)用返回的結(jié)果。也就是說lazy()方法會(huì)把最后一行作為返回值,當(dāng)我們第一次調(diào)用str完成初始化之后,后面再調(diào)用的話就直接以最后一行作為返回值返回,這其實(shí)也是延遲屬性(懶加載)的奧義所在??聪滤脑创a:

public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

?這里的actual是Kotlin的關(guān)鍵字,表示多平臺(tái)項(xiàng)目中的一個(gè)平臺(tái)相關(guān)實(shí)現(xiàn)。lazy()方法接收了一個(gè)lambda參數(shù),然后會(huì)返回一個(gè)Lazy對(duì)象,這里返回了SynchronizedLazyImpl實(shí)例。很明顯SynchronizedLazyImpl類是Lazy的子類。

?先看下Lazy,它是一個(gè)接口:

/**
 * 表示具有延遲初始化的值.
 *
 * To create an instance of [Lazy] use the [lazy] function.
 */
public interface Lazy<out T> {
    /**
     * 獲取當(dāng)前 Lazy 實(shí)例的延遲初始化值.
     * 初始化該值后,在此延遲實(shí)例(Lazy instance)的剩余生命周期內(nèi)不得更改.
     */
    public val value: T

    /**
     * 如果此延遲實(shí)例的值已初始化,則返回“true”,否則返回“false”.
     * 一旦此函數(shù)返回“true”,它將在此 Lazy 實(shí)例的剩余生命周期內(nèi)保持“true”.
     */
    public fun isInitialized(): Boolean
}

?很簡(jiǎn)單,持有一個(gè)value字段,然后一個(gè)isInitialized()方法,官方注釋也寫得很清楚。這里的<out T>是表示Lazy在泛型T上是協(xié)變的,具體可以看Kotlin的協(xié)變和逆變。提一嘴,Google爸爸的注釋寫得都非常詳細(xì),一定要去看。接著詳細(xì)來看下SynchronizedLazyImpl類的實(shí)現(xiàn):

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() {
            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)
}

?可以看到SynchronizedLazyImpl類實(shí)現(xiàn)了Lazy和Serializable接口,接收兩個(gè)參數(shù)initializer和lock,initializer就是我們的初始化邏輯函數(shù),lock則是鎖,用于獲取值時(shí)的同步操作,默認(rèn)為空。重載了Lazy接口的value(和isInitialized()方法),Lazy接口的value屬性用于獲取當(dāng)前Lazy實(shí)例的延遲初始化值,一旦初始化之后,就不能在改實(shí)例的剩余生命周期內(nèi)更改。所以重載的value屬性只有g(shù)et()方法,并沒有set()方法。

?然后自己還持有了一個(gè)私有的_value值,并設(shè)置了初始值:

@Volatile private var _value: Any? = UNINITIALIZED_VALUE

?_value使用了@Volatile注解,相當(dāng)于Java的volatile關(guān)鍵字,具有可見性和有序性,因此一旦_value值修改了,其他線程就可以看到其最新的值。

?value屬性在get()時(shí),會(huì)先判斷當(dāng)前的_value還是不是初始值(UNINITIALIZED_VALUE),如果不是就說明已經(jīng)初始化過了,直接返回即可;否則就走初始化邏輯來初始化_value值,我們看到使用了synchronized方法(類似Java的synchronized關(guān)鍵字)來保證線程安全,然后又判斷了一次_v2 !== UNINITIALIZED_VALUE,進(jìn)行雙重檢驗(yàn)。最后執(zhí)行initializer()函數(shù)進(jìn)行初始化,更新_value,再進(jìn)行返回。整個(gè)邏輯其實(shí)很清晰。

?我們上面分析的這個(gè)lazy()方法其實(shí)是最常用的一個(gè),它還有另外兩個(gè)實(shí)現(xiàn):

public actual fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer, lock)

public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
    when (mode) {
        LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
        LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
        LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
    }

?第一個(gè)其實(shí)就是把SynchronizedLazyImpl里的lock參數(shù)提到lazy()方法里來,本質(zhì)上和我們前面提到的沒區(qū)別,我們直接看第二個(gè)lazy()方法,多出來了一個(gè)LazyThreadSafetyMode類型的參數(shù),然后再根據(jù)不同模式去創(chuàng)建不同的實(shí)例。

?SYNCHRONIZED返回的也是我們剛剛分析的SynchronizedLazyImpl類;PUBLICATION則是SafePublicationLazyImpl類;而NONE是UnsafeLazyImpl類。其實(shí)我們通過名字也可以分辨出來,UnsafeLazyImpl是非線程安全的,而其他兩個(gè)是線程安全的,我們來簡(jiǎn)單看下SafePublicationLazyImpl的源碼:

private class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {

    @Volatile private var initializer: (() -> T)? = initializer
    @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    // this final field is required to enable safe initialization of the constructed instance
    private val final: Any = UNINITIALIZED_VALUE

    override val value: T
        get() {
            val value = _value
            if (value !== UNINITIALIZED_VALUE) {
                @Suppress("UNCHECKED_CAST")
                return value as T
            }

            val initializerValue = initializer
            // if we see null in initializer here, it means that the value is already set by another thread
            if (initializerValue != null) {
                val newValue = initializerValue()
                if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) {
                    initializer = null
                    return newValue
                }
            }
            @Suppress("UNCHECKED_CAST")
            return _value as T
        }

    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)

    companion object {
        private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(
            SafePublicationLazyImpl::class.java,
            Any::class.java,
            "_value"
        )
    }
}

?這邊邏輯判斷上和前面有些不同,我們可以看到initializer屬性也被加上了 @Volatile注解:

@Volatile private var initializer: (() -> T)? = initializer

?然后接著我們判斷完“value !== UNINITIALIZED_VALUE”如果不成立,也就是value還沒被初始化時(shí),我們?cè)偻伦?。這個(gè)時(shí)候,拿initializer來做判斷,“if we see null in initializer here, it means that the value is already set by another thread”,大意就是:假如我們這時(shí)發(fā)現(xiàn)initializer是空的,那么意味著value值已經(jīng)在別的線程被初始化了。為什么這么說呢,我們接下來看:

if (initializerValue != null) {
          val newValue = initializerValue()
          if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) {
                    initializer = null
                    return newValue
           }
}
return _value as T

?也就是說,如果initializer(initializerValue)為空,那么我們就直接跳過做返回操作了。那不為空的時(shí)候呢,我們是不是就得去初始化,進(jìn)到if邏輯里,先初始化拿到值(newValue),然后再通過valueUpdater的compareAndSet()做判斷,如果邏輯成立(我們先不管怎么成立),那我們就會(huì)把initializer賦值為null,完成初始化。這也就是為什么說在判斷的時(shí)候發(fā)現(xiàn)initializer為空,那么就意味著value值已經(jīng)在別的線程被初始化了的原因。那valueUpdater是啥?

companion object {
        private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(
            SafePublicationLazyImpl::class.java,
            Any::class.java,
            "_value"
        )
    }

?是Java并發(fā)包的AtomicReferenceFieldUpdater類,newUpdater是它的一個(gè)靜態(tài)方法,返回自身。那么其實(shí)上面的操作也就是通過AtomicReferenceFieldUpdater的CAS邏輯來保證了_value屬性的原子操作,因?yàn)锧Volatile是不具備原子性的。

?這也就意味著SafePublicationLazyImpl類是支持多個(gè)線程同時(shí)調(diào)用,并且可以在全部或部分線程上同時(shí)進(jìn)行初始化。但是,如果某個(gè)值已經(jīng)由另外一個(gè)線程初始化,則將返回該值,不再進(jìn)行初始化。

?UnsafeLazyImpl類因?yàn)槭欠蔷€程安全的,所以就是對(duì)value直接操作判斷,這里就不再分析了。總結(jié)下三種模式的區(qū)別:

SYNCHRONIZED => lazy()方法的默認(rèn)模式,初始化操作僅僅在首先調(diào)用的第一個(gè)線程上執(zhí)行,其他線程將引用緩存后的值。
PUBLICATION => 支持同時(shí)多個(gè)線程調(diào)用,并且可以在全部或者部分線程上同時(shí)進(jìn)行初始化。如果某個(gè)值已由另一個(gè)線程初始化,則將返回該值,而不執(zhí)行初始化。
NONE => 不是線程安全的。

結(jié)語

?本篇文章主要圍繞委托來簡(jiǎn)單介紹了Java的靜態(tài)代理和動(dòng)態(tài)代理,再到Kotlin的類委托和委托屬性,最后分析了by lazy延遲屬性。其實(shí)整體分析下來,我們會(huì)發(fā)現(xiàn)并沒有太多的難點(diǎn),Kotlin精妙的設(shè)計(jì)讓我們?cè)谔幚硎聞?wù)上更加簡(jiǎn)潔明了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文要點(diǎn)概述 辨析委托模式與代理模式 接口委托(Delegated interface) 屬性委托(Delegat...
    JayDroid閱讀 633評(píng)論 0 1
  • 參考: http://www.runoob.com/kotlin/kotlin-delegated.html 本節(jié)...
    zhaoyubetter閱讀 670評(píng)論 0 1
  • [toc] 委托是什么 委托又可以稱為代理。為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問,簡(jiǎn)單的說就是在訪問和被訪...
    Method閱讀 641評(píng)論 0 1
  • 類委托 類委托:一個(gè)類中定義的方法實(shí)際是調(diào)用另一個(gè)類的對(duì)象的方法來實(shí)現(xiàn)。DelegatedPattern.kt 問...
    Shmily魚閱讀 1,146評(píng)論 0 0
  • 前序 委托,對(duì)于很多Java開發(fā)者來說都會(huì)一面蒙蔽,我也不例外。委托,維基百科的解釋是:有兩個(gè)對(duì)象參與處理同一個(gè)請(qǐng)...
    大棋17閱讀 3,945評(píng)論 0 5

友情鏈接更多精彩內(nèi)容