委託模式已經證明是實現繼承的乙個很好的替代方式, 而 kotlin 可以零樣板**地原生支援它。這是官方對委託的描述,可能比較抽象但當你了解其意義和使用,會發現委託所帶來的方便會讓你愛不釋手,下面我們來開始學習委託吧,首先看乙個官方的例子:
inte***ce base
class baseimpl(val x: int) : base
}class derived(b: base) : base by b
上述derived類,繼承了介面base,理應實現介面base中的方法,但此處不僅沒有實現反而出現了 by b ,因為derived的類的主建構函式傳入的物件本身是實現了base介面的,這裡的by 代表 b 將會在 derived 中內部儲存, 編譯器將生成**給 b 的所有 base 的方法。這句話更直觀的理解是建立的derived的物件所執行的方法,都委託給b,相當於呼叫物件b的方法一樣(針對實現base介面的方法才會委託)。
derived 和 baseimpl類中新增乙個方法,看看此時會呼叫哪個方法:
class baseimpl(val x: int) : base
fun log()
}class derived(b: base) : base by b
}
建立derived 的物件,並分別呼叫print()和log()方法,執行結果:
02-28 02:20:40.062 4226-4226/com.example.administrator.kotlinpractise e/***************=: 10
02-28 02:20:40.062 4226-4226/com.example.administrator.kotlinpractise e/***************=: derived***************
此處可以看到print方法中國輸出的是baseimpl中的方法,而log輸出的是derived的方法,現在知道上面最後括號中那句話的意識樂吧。
委託的物件必須提供
getvalue(和setvalue)方法,因為在對被委託的物件呼叫時,系統會自動呼叫委託物件的get(),在被委託負值時,會呼叫他的set方法
class example
class delege
operator fun setvalue(thisref: any?, property: kproperty<*>, value: string)
現在建立並負值example的物件:
var example = example()
log.e("*****====", example.e)
example.e = "new example"
log.e("*****====", example.e)
現在來看看列印的日誌:
02-28 03:02:04.826 5876-5876/com.example.administrator.kotlinpractise e/getvalue**********==: getvalue
02-28 03:02:04.826 5876-5876/com.example.administrator.kotlinpractise e/*****====: com.example.administrator.kotlinpractise.example@3d2e49e
02-28 03:02:04.827 5876-5876/com.example.administrator.kotlinpractise e/setvalue**********==: new example
02-28 03:02:04.827 5876-5876/com.example.administrator.kotlinpractise e/getvalue**********==: getvalue
02-28 03:02:04.827 5876-5876/com.example.administrator.kotlinpractise e/*****====: com.example.administrator.kotlinpractise.example@3d2e49e
對於乙個唯讀屬性(即 val 宣告的),委託必須提供乙個名為 getvalue 的函式,該函式接受以下引數:
thisref —— 必須與 屬性所有者 型別(對於擴充套件屬性——指被擴充套件的型別)相同或者是它的超型別;
property —— 必須是型別 kproperty<*> 或其超型別。
這個函式必須返回與屬性相同的型別(或其子型別)。
對於乙個可變屬性(即 var 宣告的),委託必須額外提供乙個名為 setvalue 的函式,該函式接受以下引數:
thisref —— 同 getvalue();
property —— 同 getvalue();
new value —— 必須和屬性同型別或者是它的超型別。
getvalue() 或/和 setvalue() 函式可以通過委託類的成員函式提供或者由擴充套件函式提供。 當你需要委託屬性到原本未提供的這些函式的物件時後者會更便利。 兩函式都需要用 operator 關鍵字來進行標記。
接受兩個引數:初始值和修改時處理程式(handler)。 每當我們給屬性賦值時會呼叫該處理程式(在賦值後執行)。它有三個引數:被賦值的屬性、舊值和新值,在每次為變數賦值的時候委託的程式會執行
var observer : string by delegates.observable("a")
log.e("*****====",observer)
observer = "test"
log.e("*****====",observer)
輸出結果:
02-28 02:51:36.356 5496-5496/com.example.administrator.kotlinpractise e/*****====: a
02-28 02:51:36.356 5496-5496/com.example.administrator.kotlinpractise e/a*****: test
02-28 02:51:36.356 5496-5496/com.example.administrator.kotlinpractise e/*****====: test
在屬性被賦新值生效
之前 會呼叫傳遞給
vetoable
的處理程式,你可以根據條件選擇接受或拒絕賦值,引數:初始值和判斷程式(
要求返回乙個布林值
),當返回為true賦值成功,false則拒絕賦值
var observer: string by delegates.vetoable("a")
log.e("*****====", observer)
observer = "test"
log.e("*****====", observer)
observer = "new"
log.e("*****====", observer)
輸出結果:
02-28 03:02:04.827 5876-5876/com.example.administrator.kotlinpractise e/*****====: a
02-28 03:02:04.827 5876-5876/com.example.administrator.kotlinpractise e/*****====: a
02-28 03:02:04.827 5876-5876/com.example.administrator.kotlinpractise e/*****====: new
乙個常見的用例是在乙個對映(map)裡儲存屬性的值。 這經常出現在像解析 json 或者做其他「動態」事情的應用中。 在這種情況下,你可以使用對映例項自身作為委託來實現委託屬性。
class user(val map: map)
在這個例子中,建構函式接受乙個對映引數:
val user = user(mapof(
"name" to "john doe",
"age" to 25
))
委託屬性會從這個對映中取值(通過字串鍵——屬性的名稱):
println(user.name) // prints "john doe"println(user.age) // prints 25
這也適用於
var
屬性,如果把唯讀的
map換成
mutablemap
的話:class
mutableuser
(val
map:mutablemap
<
string
,any
?>
) 到這裡大家對委託應該有了初步的了解,個人感覺委託在開發中還是很實用的,比如一些需要需要讀取和設定的資料,可以使用屬性委託免去一些**且邏輯性更好,之後還會繼續出一遍關於委託更深入的應用,今天暫時到這吧。
kotlin學習之類委託(八)
如果我們需要乙個集合類,含有mutablecollection的所有功能,並可以修改兩個方法,add和addall,那麼我們需要寫乙個新的類繼承mutablecollection,並把乙個mutablecollection成員放到裡面,覆蓋並修改他的所有方法,並修改add和addall方法。clas...
Kotlin學習 Kotlin委託
委託模式是軟體設計模式中的一項基本技巧。在委託模式中,有兩個物件參與處理同乙個請求,接受請求的物件將請求委託給另乙個物件來處理。kotlin 直接支援委託模式,更加優雅,簡潔。kotlin 通過關鍵字 by 實現委託 類的委託即乙個類中定義的方法實際是呼叫另乙個類的物件的方法來實現的。以下例項中派生...
Kotlin基礎 委託
類委託 屬性委託 2.1.方法一 可以按需繼承readonlyproperty readwriteproperty兩個介面中的乙個 2.2.方法二 自己定義,但方法引數必須和 1 中介面的方法引數一致 標準委託 3.1.延遲屬性 lazy 3.2.可觀察屬性 observable 3.3.把屬性儲存...