Kotlin委托
Kotlin委托
1.Kotlin
中的委托有两种形式,一种是委托模式,一种是委托属性。
2.委托模式是设计模式中的一种,它是有两个对象参与处理同意请求,接受请求的对象将请求委托给另一个对象来处理。Kotlin
语法对于这种模式提供了一个简易的写法。
委托模式的好处是可以使用聚合来代替继承。
看一下代码,委托模式的写法为:
// 一个接口
interface Base {
fun print()
}
// 第一个子类
class BaseImple1(val x:Int):Base {
override fun print() { print(x) }
}
// 第二个子类
class BaseImple2(val baseImple1:BaseImple1) {
fun print() { baseImple1.print() }
}
// 第三个子类
class BaseImple3(val baseImple1:BaseImple1) :Base {
override fun print() { baseImple1.print(x) }
}
第二个子类和第三个子类都是委托了第一个子类来进行函数的处理的。
Kotlin
针对于第三个子类的委托模式可以简化写法为:
// 第三个子类
class BaseImple3(val baseImple1:BaseImple1) :Base by baseImple1
对于BaseImple3
对象的调用函数等行为,委托转发给了baseImple1
此对象。
注意事项:
- 规定必须要使用接口,而不能使用抽象类。
- 此
by
关键字,委托的只是接口类中的函数,非接口中定义函数还是调用此对象所定义的函数和属性,不能委托。
3.委托属性
- 延迟属性
- 可观察属性
- 多个属性保存在一个
map
中
3.1 语法为:val/var <属性名>: <类型> by <表达式>
,委托属性需要提供getValue()
和setValue()
方法
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
3.2 延迟属性
lazy()
第一次调用会执行lambda
表达式并且记录结果,后续调用只会返回结果记录。此函数是线程安全的,不需要在外部添加额外同步代码,也可以通过传入参数来指定,源码为:
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
三种加载模式:
-
SYNCHRONIZED
,调用SynchronizedLazyImpl
-
PUBLICATION
,调用SafePublicationLazyImpl
-
NONE
,调用UnsafeLazyImpl
SynchronizedLazyImpl
源码分析:
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
// 加锁
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
// 第一次会走到这里执行lambda表达式,加结果保存到_value中,第二次则直接返回_value值,而不再执行lambda表达式中的内容
val typedValue = initializer!!()
_value = typedValue
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
内部有一个属性保存lambda
表达式所执行的值,再次调用则直接返回,无需执行lambda
。
SafePublicationLazyImpl
源码分析:
private class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {
@Volatile private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// this final field is required to enable safe publication of constructed instance
private val final: Any = UNINITIALIZED_VALUE
override val value: T
get() {
val value = _value
if (value !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST")
return value as T
}
val initializerValue = initializer
// if we see null in initializer here, it means that the value is already set by another thread
// 第一次执行initializerValue,不回为null,则对value的值进行更新,initializer设置为null;
if (initializerValue != null) {
val newValue = initializerValue()
if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) {
initializer = null
return newValue
}
}
@Suppress("UNCHECKED_CAST")
return _value as T
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
companion object {
private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater(
SafePublicationLazyImpl::class.java,
Any::class.java,
"_value"
)
}
}
它是在不需要加锁,并发执行的情况下,可以通过此类来获取值,同lazy
类似,都是第一次的时候执行lambda
表达式,然后再次执行就直接通过此类中的属性返回值即可,区别只是是否加锁,可以在多个线程中执行。
UnsafeLazyImpl
源码:
internal class UnsafeLazyImpl<out T>(initializer: () -> T) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
private var _value: Any? = UNINITIALIZED_VALUE
override val value: T
get() {
if (_value === UNINITIALIZED_VALUE) {
_value = initializer!!()
initializer = null
}
@Suppress("UNCHECKED_CAST")
return _value as T
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
这个只是简单的进行了一下判断,当前若有值,则返回,没有的话就执行lambda
保存表达式的值,跟锁等无关,最好在单线程中使用,要不然会有同步问题。
4.可观察属性
Delegates.observable()
需要两个参数,一个是此值的初始值,一个是此属性被修改时lambda
的处理程序。
Delegates.vetoable()
需要参数同上一致,只不过是lambda
的处理时机不一致,上面的是在属性修改之后,这个实在属性修改之前。
5.属性存储在map
映射中
可以使用map
来对类的属性保存,官网上的例子:
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
6.实际使用中的一些写法:
标准委托要自己写的话有ReadOnlyProperty
,ReadWriteProperty
两个接口,也提供了Delegates
类中的函数可以来进行委托,如果需要仿照此类写即可。
kotlin
中applicationcontext
的获取方式可以这么写:
class App : Application() {
var instance by Delegates.notNull<Application>()
override fun onCreate() {
super.onCreate()
instance = this
}
}
延迟加载基本使用lazy
就可满足需求,下面是在网上看到的一个Android
中sp
的使用方法,觉得不错,贴一下代码:
class Preference<T>(private val context: Context, private val name: String,
private val default: T) {
private val prefs: SharedPreferences by lazy {
context.getSharedPreferences("default", Context.MODE_PRIVATE)
}
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = findPreference(name, default)
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
putPreference(name, value)
}
@Suppress("UNCHECKED_CAST")
private fun findPreference(name: String, default: T): T = with(prefs) {
val res: Any = when (default) {
is Long -> getLong(name, default)
is String -> getString(name, default)
is Int -> getInt(name, default)
is Boolean -> getBoolean(name, default)
is Float -> getFloat(name, default)
else -> throw IllegalArgumentException("This type can be saved into Preferences")
}
res as T
}
@SuppressLint("CommitPrefEdits")
private fun putPreference(name: String, value: T) = with(prefs.edit()) {
when (value) {
is Long -> putLong(name, value)
is String -> putString(name, value)
is Int -> putInt(name, value)
is Boolean -> putBoolean(name, value)
is Float -> putFloat(name, value)
else -> throw IllegalArgumentException("This type can't be saved into Preferences")
}.apply()
}
}
// 单例调用此函数
object DelegatesExt {
fun <T> preference(context: Context, name: String,
default: T) = Preference(context, name, default)
}
// 具体使用
private var zipCode: Long by DelegatesExt.preference(this, ZIP_CODE, DEFAULT_ZIP)
这个写法,就是使用了委托属性,然后操作属性即可,而不需要再像原来一样写一大堆的样板代码了。