美文网首页
我的Kotlin 学习之路(四)Kotlin之委托

我的Kotlin 学习之路(四)Kotlin之委托

作者: 活着工作室 | 来源:发表于2017-06-08 11:26 被阅读0次

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

    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}]}
    
    
    

    即使以后再有其他网络请求方式,只需要继续以上的方式即可,一样的入参,一样的回调方式,利用委托后可使用你的代码整齐,划一。还用那三句话来结束吧

    (把权力关进制度的笼子里)
    (把权力关进制度的笼子里)
    (把权力关进制度的笼子里)

    相关文章

      网友评论

          本文标题:我的Kotlin 学习之路(四)Kotlin之委托

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