一、什么叫委托? 看看官文解釋
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}]}
即使以后再有其他網絡請求方式,只需要繼續以上的方式即可,一樣的入參,一樣的回調方式,利用委托后可使用你的代碼整齊,劃一。還用那三句話來結束吧
(把權力關進制度的籠子里)
(把權力關進制度的籠子里)
(把權力關進制度的籠子里)