一、什么叫委托? 看看官文解释
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}]}
即使以后再有其他网络请求方式,只需要继续以上的方式即可,一样的入参,一样的回调方式,利用委托后可使用你的代码整齐,划一。还用那三句话来结束吧
(把权力关进制度的笼子里)
(把权力关进制度的笼子里)
(把权力关进制度的笼子里)