Kotlin類委托(二):實現(xiàn)原理及注意事項

相關(guān)文章

Kotlin 類委托(一):如何把一個列表頁優(yōu)化到十幾行代碼

Kotlin 類委托(二):實現(xiàn)原理及注意事項

上章留下的問題

? 有看過我上一篇文章的讀者可能會有疑問,為什么對網(wǎng)絡(luò)數(shù)據(jù)的請求要使用 lambda 對象 getArticleList 的方式調(diào)用,在不同的 viewModelinit 方法塊中進行設(shè)置,為什么不使用在 接口 中聲明,在子類中 重寫 的方式實現(xiàn)呢?我們改用這樣的方式實現(xiàn)看一下效果:

  1. ArticleListPagingInterface 中添加方法用于獲取數(shù)據(jù)

    /** 分頁獲取數(shù)據(jù)相關(guān)接口 */
    interface ArticleListPagingInterface {
    
        ... 省略部分代碼 ...
        
        /** 獲取文章列表數(shù)據(jù) */
        fun getArticleList(num: Int): LiveData<NetResult<ArticleListEntity>>
        
        ... 省略部分代碼 ...
    }
    
  2. ArticleListPagingInterfaceImpl 中添加對應(yīng)實現(xiàn)

    /** 分頁獲取數(shù)據(jù)相關(guān)接口實現(xiàn)類 */
    class ArticleListPagingInterfaceImpl
        : ArticleListPagingInterface {
             
        ... 省略部分代碼 ...
        
        /** 獲取文章列表數(shù)據(jù) */
        override fun getArticleList(num: Int): LiveData<NetResult<ArticleListEntity>> {
            // 需要具體業(yè)務(wù)實現(xiàn)
            throw RuntimeException("You must override this method!")
        }
            
        ... 省略部分代碼 ...
    }
    
  3. BjnewsArticlesViewModel 中重寫使用

    class BjnewsArticlesViewModel(
            private val repository: ArticleRepository
    ) : BaseViewModel(),
            ArticleCollectionInterface by ArticleCollectionInterfaceImpl(repository),
            ArticleListPagingInterface by ArticleListPagingInterfaceImpl() {
    
        /** 公眾號 id */
        var bjnewsId = ""
        
        override fun getArticleList(num: Int): LiveData<NetResult<ArticleListEntity>> {
            val result = MutableLiveData<NetResult<ArticleListEntity>>()
                viewModelScope.launch {
                    try {
                        result.value = repository.getBjnewsArticles(bjnewsId, num)
                    } catch (throwable: Throwable) {
                        Logger.t("NET").e(throwable, "getArticleList")
                    }
                }
            return result
        }
    }
    
  4. 運行查看效果,然后你會發(fā)現(xiàn)每次獲取數(shù)據(jù)都會拋出異常,重寫的 getArticleList 方法并沒有生效,這是為什么?

類委托實現(xiàn)原理

查看 Kotlin 對應(yīng)的 Java 代碼

? kotlin 語法中很多都是 語法糖,為了能夠更好的理解這些語法的規(guī)則和使用,我們可以閱讀 kotlin 代碼對應(yīng)的 Java 代碼,Kotlin 插件 也為我們提供了這樣的功能:

?
sXe51H.md.png

? 通過依次點擊 Tools -> Koltin -> Show Kotlin Bytecode -> Decompile,Kotlin 插件 會為我們生成 BjnewsArticleViewModel.decompiled.java 文件,這個就是 BjnewsArticleViewModel.kt 對應(yīng)的 Java 代碼。

類委托的實現(xiàn)

? 通過對 BjnewsArticleViewModel.decompiled.java 文件的查看,我們發(fā)現(xiàn)關(guān)鍵字 by 之后的具體實現(xiàn)對象在 java 中被聲明成了 final 修飾的成員變量

?
變量聲明

? 并且在構(gòu)造方法中對其進行了初始化

?
變量初始化

? 接口中的方法實現(xiàn)實際上都是調(diào)用了對應(yīng)對象的方法

?
方法重寫

? 所以 類委托 的實現(xiàn)實際就是 將接口中對應(yīng)的方法、變量委托給對應(yīng)的類實現(xiàn)。

之前的問題

? 那么我們回到之前的問題,為什么重寫了的方法不起作用?

?
重寫獲取數(shù)據(jù)方法

? 我們可以看到 getArticleList 方法已經(jīng)是重寫了的,但是追蹤一下你會發(fā)現(xiàn)重寫的這個方法并沒有任何地方調(diào)用,當(dāng)我們進行網(wǎng)絡(luò)請求的時候,觸發(fā)時起源于 ArticleListPagingInterface 中的 pageNumber 的變動,而由于我們使用了 類委托,在 BjnewsArticleViewModel 中實際進行刷新獲取數(shù)據(jù)的調(diào)用的時代理對象 ArticleListPagingInterfaceImpl 中的方法,也就是說加載數(shù)據(jù)走的是代理對象里面的邏輯,而在 ArticleListPagingInterfaceImplgetArticleList 方法固定拋出異常,因此每次請求數(shù)據(jù)都會拋出異常。所以對于不同界面可能有的不同數(shù)據(jù)獲取方式,我們選擇了聲明一個 lambda 對象用于存儲獲取數(shù)據(jù)的請求,在不同界面設(shè)置不同的獲取方式。

因此,使用 類委托 我們確實可以達到 一個類繼承多個類 的效果,但是我們需要知道的是這種方式終究不是繼承,不能一味的按照繼承的思路來實現(xiàn)。

總結(jié)

? 最后,我們得出結(jié)論,使用 類委托 我們確實可以達到 一個類繼承多個類 的效果,但是我們需要知道的是這種方式終究不是繼承,不能一味的按照繼承的思路來實現(xiàn),需要注意以下幾點:

  1. 如果一個 接口 中的方法被 委托類 中的其他方法調(diào)用,那么僅僅重寫 實現(xiàn)類 中的方法是無效的,必須同時重寫 委托類 中調(diào)用改方法的方法,或者將對應(yīng)邏輯修改為對象實現(xiàn)。
  2. 基于上面一條,不管 委托類 中實現(xiàn)了多少個接口,添加了多少方法,對于 實現(xiàn)類 來說都是不可觸及的,class A: B by BImpl() 中,不管 BImpl 有多少邏輯,對于 A 來說,關(guān)注的永遠都只有 B 中聲明的方法及變量。

? 那么關(guān)于 Kotlin類委托 到這里就說完了,感謝大家的耐心觀看,我是 WangJie0822 ,一個普普通通的程序猿,歡迎關(guān)注。

作者: WangJie0822
鏈接: http://www.wangjie0822.top/posts/438581be
來源: WangJie0822
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。

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

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

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