我的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"//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阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 得能莫忘:掌握了技能,要时常加以练习,不要遗忘。 每日一字,修身修心!
    雨林中的阳光阅读 205评论 0 2
  • 几个同事在家里聚餐,火锅饺子烧烤,三样东西吃下来,一个个都是从头到尾,战斗力完全不减。 我还是喜欢面食,喜欢擀面,...
    云小5阅读 268评论 0 0
  • 2017年7月11日 周二 天气晴 昨天下班之后去看了房,因为现在住的合同到期,而且感觉并不是很满意,所以想搬,但...
    道道樱木花道阅读 575评论 0 0
  • 瘦了,前段时间还胖了是不是称的原因呢,可能是穿的少了吧!每个人都会有对自己不满意的地方,但是人没有完美的,不需要处...
    河悦悦阅读 140评论 0 0