在委托模式中帮孔,有兩個(gè)對(duì)象參與處理同一個(gè)請(qǐng)求碉就,接受請(qǐng)求的對(duì)象將請(qǐng)求委托給另一個(gè)對(duì)象來(lái)處理钳吟。
類委托
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val b = Bean("hello world")
Delegation(b).delegate()
}
}
interface IDelegateListener {
fun delegate()
}
class Bean(val s: String) : IDelegateListener {
override fun delegate() {
println("bean ----> $s")
}
}
class Delegation(delegateListener: IDelegateListener) : IDelegateListener by delegateListener
由輸出結(jié)果可以看到:Delegation
類并沒有實(shí)現(xiàn) IDelegateListener
中的 delegate()
方法手素,而是通過(guò)by
這個(gè)關(guān)鍵字滴铅,將本應(yīng)該實(shí)現(xiàn)的方法委托給了Bean
,由Bean
來(lái)實(shí)現(xiàn)方法
委托屬性
定義一個(gè)委托屬性的語(yǔ)法是:
val/var <property name>: <Type> by <expression>
,by
后面的就是屬性的委托戳葵。委托屬性不需要實(shí)現(xiàn)接口,只需要用operator
修飾的setValue()
getValue
函數(shù)汉匙。如果是val屬性 則不用提供setValue()
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bean = Bean()
println("bean ---> ${bean.string}")
bean.string="2"
println("bean ---> ${bean.string}")
}
}
class Bean {
var string: String by Delegator()
}
class Delegator {
var temp = "1"
operator fun getValue(ref: Any?, p: KProperty<*>): String {
return "Delegator --> ${p.name} --> $temp"
}
operator fun setValue(ref: Any?, p: KProperty<*>, value: String) {
temp = value
}
}
參數(shù)說(shuō)明:
-
ref
屬性擁有者 -
p
屬性的描述 -
value
屬性的值
標(biāo)準(zhǔn)委托
延遲屬性 lazy
通過(guò)lazy
可以定義一個(gè)懶加載屬性拱烁,只有val
類型的屬性才能延遲初始化,且只初始化一次噩翠,lazy()
是接受一個(gè) lambda 并返回一個(gè) Lazy <T>
實(shí)例的函數(shù)戏自,返回的實(shí)例可以作為實(shí)現(xiàn)延遲屬性的委托: 第一次調(diào)用 get()
會(huì)執(zhí)行已傳遞給 lazy()
的 lambda 表達(dá)式并記錄結(jié)果, 后續(xù)調(diào)用 get()
只是返回記錄的結(jié)果伤锚。
class MainActivity : AppCompatActivity() {
val lazyValue:String by lazy {
println("1 ---->賦值")
"lazy"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
println("2 ---->$lazyValue")
println("3 ---->$lazyValue")
}
}
可以從運(yùn)行結(jié)果看出:只有在第一次使用的時(shí)候才將
"lazy"
賦值
默認(rèn)情況下擅笔,對(duì)于 lazy
屬性的求值是同步鎖的(synchronized):該值只在一個(gè)線程中計(jì)算,并且所有線程會(huì)看到相同的值屯援。如果初始化委托的同步鎖不是必需的猛们,這樣多個(gè)線程可以同時(shí)執(zhí)行,那么將 LazyThreadSafetyMode.PUBLICATION
作為參數(shù)傳遞給 lazy()
函數(shù)狞洋。 而如果你確定初始化將總是發(fā)生在單個(gè)線程弯淘,那么你可以使用 LazyThreadSafetyMode.NONE
模式, 它不會(huì)有任何線程安全的保證和相關(guān)的開銷吉懊。
可觀察屬性 Observable
Delegates.observable()
接受兩個(gè)參數(shù):初始值和修改時(shí)處理程序(handler)庐橙。 每當(dāng)我們給屬性賦值時(shí)會(huì)調(diào)用該處理程序(在賦值后執(zhí)行)假勿。它有三個(gè)參數(shù):被賦值的屬性、舊值和新值
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val observableUse = ObservableUse()
observableUse.s = "1"
observableUse.i = "2"
println("observable ----> ${observableUse.s}")
println("observable ----> ${observableUse.i}")
}
}
class ObservableUse {
var s: String by Delegates.observable("0") { property, oldValue, newValue ->
println("observable ----> $property,$oldValue,$newValue")
}
var i: String by Delegates.vetoable("3") { property, oldValue, newValue ->
newValue.length > oldValue.length
}
}
通過(guò)可觀察屬性态鳖,就可以實(shí)現(xiàn)一些觀察者模式的方法转培,如果你想能夠截獲一個(gè)賦值并“否決”它,就使用
vetoable()
取代 observable()
郁惜。 在屬性被賦新值生效之前會(huì)調(diào)用傳遞給 vetoable
的處理程序堡距。
實(shí)際應(yīng)用場(chǎng)景
通過(guò)委托,我們可以封裝一些工具類兆蕉,例如 Intent 取值 SharedPrefrences 取值等:
/**
* kotlin 委托傳值工具
*/
class ExtraDelegator<out T>(private val extraKey:String , private val defaultValue:T) {
private var extra: T? = null
operator fun getValue(thisRef: AppCompatActivity, property: KProperty<*>): T {
extra = getExtra(extra, extraKey, thisRef)
return extra ?: defaultValue
}
operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
extra = getExtra(extra, extraKey, thisRef)
return extra ?: defaultValue
}
fun <T> extraDelegate(extra: String, default: T) = ExtrasDelegate(extra, default)
fun extraDelegate(extra: String) = extraDelegate(extra, null)
@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraKey: String, thisRef: AppCompatActivity): T? =
oldExtra ?: thisRef.intent?.extras?.get(extraKey) as T?
@Suppress("UNCHECKED_CAST")
private fun <T> getExtra(oldExtra: T?, extraKey: String, thisRef: Fragment): T? =
oldExtra ?: thisRef.arguments?.get(extraKey) as T?
}
使用:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 傳值
content_tv.setOnClickListener {
val intent = Intent(this@MainActivity, TestActivity::class.java)
intent.putExtra("string","value")
startActivity(intent)
}
}
}
class TestActivity:AppCompatActivity(){
val string:String? by extraDelegate("string") // 通過(guò)委托接收
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test)
println("TestActivity ------> $string")
}
}
結(jié)語(yǔ)
通過(guò)委托和擴(kuò)展函數(shù)可以封裝很多有趣的工具類羽戒,從Java
過(guò)度到Kotlin
的感覺就好像從 Eclipse
過(guò)渡到 Android Studio
一開始覺得麻煩,但是用一用就覺得:誒虎韵,還可以易稠,到現(xiàn)在已經(jīng)基本不想再用Java
寫了 , 對(duì)于新的東西包蓝,還是要去敢于嘗試驶社。