我的Kotlin 學習之路(四)Kotlin之委托

一、什么叫委托? 看看官文解釋

The Delegation pattern has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code.
A class Derived can inherit from an interface Base and delegate all of its public methods to a specified object:

interface Base {
    fun print()
}

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

class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // 輸出 10
}

意思是,Derived將Base的所有public方法委托到了b里 。。。
光看這樣的解釋,我一直沒有明白委托的意義何在?為什么不直接用b.print()呢,反正b已經new出來了啊?為什么還要用Derived(b).print()呢?相信你也有這樣的疑問吧
為了解釋這個,我們換一個場景,官方的例子有點抽象

場景一:用掛號說事。。。

/**
 * 掛號接口
 * Created by ff on 2017/6/5.
 */
interface Base {
    fun register ()//掛號
}

掛號目前有3種實現方法

/**
 * 電話掛號的實現類
 */
class PhoneRegistered : Base {
    override fun register () {
        println("114掛號")
    }
}


/**
 * 網絡掛號的實現類
 */
class NetRegistered : Base {
    override fun register () {
        println("網絡掛號")
    }
}


/**
 * 掛號機掛號的實現類
 */
class MachineRegistered : Base {
    override fun register () {
        println("掛號機掛號")
    }
}

寫到這沒有人不明白吧,如果不明白,請return java基礎


/**
 * 委托類 把Base的所有public方法委托給d 實現
 */
class DelegateRegister (d : Base): Base by d

這個DelegateRegister就是委托類,d是委托的對象(specified object),Base的實現類,也就是委托人。被委托人呢當然是Base,所以才有了 Base by d

使用是這樣

fun main(args: Array<String>) {
    DelegateRegister(PhoneRegistered()).register()//把register方法委托給PhoneRegistered去實現(用電話去掛號)
    DelegateRegister(NetRegistered()).register()//把register方法委托給NetRegistered去實現 (用網絡去掛號)
    DelegateRegister(MachineRegistered()).register()//把register方法委托給RegisteredMachine去實現(用掛號機去掛號)
}

打印結果
114掛號
網絡掛號
掛號機掛號

不管你用哪種方式去實現,都要通過DelegateRegister這個委托類去調用,這個委托類已經明確給明了被委托人Base,需要委托的事情register(),因此你不可能用這個委托類去做別的事情。比如你除了做register()掛號這件事以外,其他的事沒讓委托人去做,委托人也不可能去做,再者你也不可能幫第三個人去掛號,只能給Base的人掛,這就是委托的精神,委托一個人做N件事,所有的行為都在牢牢的控制中,這就是委托的作用
(把權力關進制度的籠子里)
(把權力關進制度的籠子里)
(把權力關進制度的籠子里)

下面說說委托屬性(Delegated Properties)
還用上面的例子進行擴展
1、延時委托

/**
 * 電話掛號的實現類
 */
class PhoneRegistered : Base {
    override fun register () {
        println("114掛號")
    }

    //標準委托 此方法委托lazy 加載,只有調用此常量時才會初始化,之后的調用只返回結果x
    val money:Int by lazy {
        var x = 1
        while (x < 200){
            x++
        }
        x
    }
}

by lazy 就是標準委托,只用當第一次調用money時才會初始化變量,計算并返回x。在以后的調用中僅僅返回已經計算好的x

2、普通委托屬性


/**
 * 網絡掛號的實現類
 */
class NetRegistered : Base {
    override fun register () {
        println("網絡掛號 url = $netUrl")
    }

    var netUrl:String by Delegete() //委托屬性給 Delegete類的get和set方法
}

/**
 * 委托屬性 強制get set
 */
class Delegete{
    operator fun  getValue(netBuy: NetRegistered, property: KProperty<*>): String {
        return "http://www.${netBuy.javaClass.name}.${property.name}.com"
    }
    operator fun  setValue(netBuy: NetRegistered, property: KProperty<*>, s: String) {}

}


fun main(args: Array<String>) {
    DelegateRegister(NetRegistered()).register()//把register方法委托給NetRegistered去實現 (用網絡去掛號)
}

打印結果
網絡掛號 url = http://www.NetRegistered.netUrl.com

3、可觀察屬性 Observable


/**
 * 掛號機掛號的實現類
 */
class MachineRegistered : Base {
    override fun register () {
        println("掛號機掛號")
    }

    var opreaoter:String by Delegates.observable("Default"){//可觀察屬性 Observable
        kProperty: KProperty<*>, old: String, new: String -> println("$old -> $new")

    }
}


fun main(args: Array<String>) {
    var m = MachineRegistered()
    m.opreaoter = "1號機"
    m.opreaoter = "2號機"
}

打印結果
Default -> 1號機
1號機 -> 2號機

委托及委托屬性介紹完了,會不會稍微清楚一點,我用了一周時間才算明白點,如果第一次看完了還不明白,沒關系,我還準備了場景二,這個場景是面向開發的,每個人都會遇到,網絡請求的框架有很多,更新也更快,從Httpconnection 到 volley 到 okhttp ,現在還有rxjava等,考慮到這也是適用一種委托的思維,所以我寫了下面這個例子,希望你看了后會更明白點為什么要用委托,什么時候用?直接上整齊的代碼,提高可讀性,注釋我都寫在里面了

場景二:用網絡請求說事。。。


/**
 * Base基類 請求的方法
 */
abstract class BaseRequest {
    abstract fun onRequest()
    init {
        print(this.javaClass.name)//被委托人的名字
    }
}

/**
 * 委托接口
 */
interface InterRequest {
    fun onSuccess(json: String)
    fun onFailed(responseCode: Int)
}

/**
 * 委托類
 */
class DelegateRequest(d: InterRequest) : InterRequest by d

/**
 * Volley實現的委托對象
 */
class VolleyRequest(val url: String?, val map: Map<String, String>?, val mListener: InterRequest?) : BaseRequest(), InterRequest {
    init {
        onRequest()
    }

    //do request 暫時用kt模擬實現,實際中用Volley自已的實現方法
    override fun onRequest() {
        var jsonStr: String? = null
        try {
            jsonStr = URL(url).readText()
            jsonStr?.let {
                onSuccess(it)
            }
        } catch (e: Exception) {
            onFailed(500)// 假設是500
        }

    }

    override fun onSuccess(json: String) {
        mListener?.onSuccess(json)
    }

    override fun onFailed(responseCode: Int) {
        mListener?.onFailed(responseCode)
    }

}

/**
 * OkHttp實現的委托對象
 */
class OkHttpRequest(val url: String?, val map: Map<String, String>?, val mListener: InterRequest?) : BaseRequest(), InterRequest {
    init {
        onRequest()
    }

    //do request 暫時用kt模擬實現,實際中用okHttp自已的實現方法
    override fun onRequest() {
        var jsonStr: String? = null
        try {
            jsonStr = URL(url).readText()
            jsonStr?.let {
                onSuccess(it)
            }
        } catch (e: Exception) {
            onFailed(500)// 假設是500
        }
    }

    override fun onSuccess(json: String) {
        mListener?.onSuccess(json)
    }

    override fun onFailed(responseCode: Int) {
        mListener?.onFailed(responseCode)
    }
}


fun main(args: Array<String>) {
    val url = "http://api.openweathermap.org/data/2.5/forecast/daily?mode=json&units=metric&cnt=7&APPID=15646a06818f61f7b8d7823ca833e1ce&id=2038349"http://google天氣
    var map = hashMapOf(Pair("", ""))


    //把BaseRequest的所有public方法委托給VolleyRequest去實現
    DelegateRequest(VolleyRequest(url, map, object : InterRequest {
        override fun onSuccess(json: String) {
            println(" onSuccess : $json")
        }

        override fun onFailed(responseCode: Int) {
            println(" onFailed : $responseCode")
        }
    }))


    //同理,委托給OkHttpRequest去實現
    DelegateRequest(OkHttpRequest(url, map, object : InterRequest {
        override fun onSuccess(json: String) {
            println(" onSuccess : $json")
        }

        override fun onFailed(responseCode: Int) {
            println(" onFailed : $responseCode")
        }
    }))
}


打印結果
VolleyRequest onSuccess : {"city":{"id":2038349,"name":"Beijing Shi","coord":{"lon":116.3971,"lat":39.9169},"country":"CN","population":0},"cod":"200","message":0.3792573,"cnt":7,"list":[{"dt":1496980800,"temp":{"day":37,"min":22.09,"max":38.25,"night":22.09,"eve":36.08,"morn":37},"pressure":995.08,"humidity":51,"weather":[{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"}],"speed":1.76,"deg":54,"clouds":0},{"dt":1497067200,"temp":{"day":24.49,"min":14.73,"max":26.34,"night":18.54,"eve":26.34,"morn":14.73},"pressure":1001.59,"humidity":38,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"speed":2.36,"deg":136,"clouds":44},{"dt":1497153600,"temp":{"day":26.01,"min":13.3,"max":28.87,"night":18.92,"eve":28.87,"morn":13.3},"pressure":1000.1,"humidity":40,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"speed":1.76,"deg":127,"clouds":8,"rain":0.9},{"dt":1497240000,"temp":{"day":29.38,"min":19.55,"max":29.38,"night":19.55,"eve":23.96,"morn":23.98},"pressure":967.13,"humidity":0,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"speed":2.81,"deg":199,"clouds":45,"rain":2.88},{"dt":1497326400,"temp":{"day":25.55,"min":16.7,"max":25.55,"night":16.7,"eve":20.87,"morn":24.06},"pressure":968.38,"humidity":0,"weather":[{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"}],"speed":1.82,"deg":191,"clouds":24,"rain":11.01},{"dt":1497412800,"temp":{"day":26.35,"min":16.51,"max":26.35,"night":16.51,"eve":22.76,"morn":21.88},"pressure":969.55,"humidity":0,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"speed":2.22,"deg":63,"clouds":10,"rain":1.7},{"dt":1497499200,"temp":{"day":31.85,"min":18.59,"max":31.85,"night":18.59,"eve":25.81,"morn":24.3},"pressure":968.38,"humidity":0,"weather":[{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"}],"speed":1.57,"deg":21,"clouds":0}]}
OkHttpRequest onSuccess : {"city":{"id":2038349,"name":"Beijing Shi","coord":{"lon":116.3971,"lat":39.9169},"country":"CN","population":0},"cod":"200","message":0.3792573,"cnt":7,"list":[{"dt":1496980800,"temp":{"day":37,"min":22.09,"max":38.25,"night":22.09,"eve":36.08,"morn":37},"pressure":995.08,"humidity":51,"weather":[{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"}],"speed":1.76,"deg":54,"clouds":0},{"dt":1497067200,"temp":{"day":24.49,"min":14.73,"max":26.34,"night":18.54,"eve":26.34,"morn":14.73},"pressure":1001.59,"humidity":38,"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"speed":2.36,"deg":136,"clouds":44},{"dt":1497153600,"temp":{"day":26.01,"min":13.3,"max":28.87,"night":18.92,"eve":28.87,"morn":13.3},"pressure":1000.1,"humidity":40,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"speed":1.76,"deg":127,"clouds":8,"rain":0.9},{"dt":1497240000,"temp":{"day":29.38,"min":19.55,"max":29.38,"night":19.55,"eve":23.96,"morn":23.98},"pressure":967.13,"humidity":0,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"speed":2.81,"deg":199,"clouds":45,"rain":2.88},{"dt":1497326400,"temp":{"day":25.55,"min":16.7,"max":25.55,"night":16.7,"eve":20.87,"morn":24.06},"pressure":968.38,"humidity":0,"weather":[{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"}],"speed":1.82,"deg":191,"clouds":24,"rain":11.01},{"dt":1497412800,"temp":{"day":26.35,"min":16.51,"max":26.35,"night":16.51,"eve":22.76,"morn":21.88},"pressure":969.55,"humidity":0,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"speed":2.22,"deg":63,"clouds":10,"rain":1.7},{"dt":1497499200,"temp":{"day":31.85,"min":18.59,"max":31.85,"night":18.59,"eve":25.81,"morn":24.3},"pressure":968.38,"humidity":0,"weather":[{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"}],"speed":1.57,"deg":21,"clouds":0}]}


即使以后再有其他網絡請求方式,只需要繼續以上的方式即可,一樣的入參,一樣的回調方式,利用委托后可使用你的代碼整齊,劃一。還用那三句話來結束吧

(把權力關進制度的籠子里)
(把權力關進制度的籠子里)
(把權力關進制度的籠子里)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • 得能莫忘:掌握了技能,要時常加以練習,不要遺忘。 每日一字,修身修心!
    雨林中的陽光閱讀 228評論 0 2
  • 幾個同事在家里聚餐,火鍋餃子燒烤,三樣東西吃下來,一個個都是從頭到尾,戰斗力完全不減。 我還是喜歡面食,喜歡搟面,...
    云小5閱讀 288評論 0 0
  • 2017年7月11日 周二 天氣晴 昨天下班之后去看了房,因為現在住的合同到期,而且感覺并不是很滿意,所以想搬,但...
    道道櫻木花道閱讀 588評論 0 0
  • 瘦了,前段時間還胖了是不是稱的原因呢,可能是穿的少了吧!每個人都會有對自己不滿意的地方,但是人沒有完美的,不需要處...
    河悅悅閱讀 154評論 0 0