kotlin入门——委托模式
委托:
kotlin中的委托类似于java中的代理模式kotlint中通过 by 关键字修饰 by 后面跟着的就是你委托的对象,举个通俗易懂例子,大学生上网找代写论文:
首先:定义需要委托的业务,本例子就是写论文
/**
* 约束类 场景中的业务
*/
interface Paper {
// 写论文
fun writePagers()
}
然后是被委托的对象,场景中的代写写手
/**
* 被委托的对象,场景中的论文代写的写手
*/
class RealWriter(val name : String) : Paper {
override fun writePagers() {
print("${name}进行论文写作")
}
}
最后是委托对象,场景中的大学生
/**
* 委托的对象, 场景中的大学生
*/
class LowCollegeStudent(var writer: Paper) : Paper by writer
测试场景,定义了一个叫张艾鱼的写手,把他委托给了大学生,大学生写论文的业务就交给他来完成
/**
* 测试
*/
fun main(){
val realWriter = RealWriter("张艾鱼");
val student = LowCollegeStudent(realWriter)
student.writePagers();
}
运行结果:张艾鱼进行论文写作
注:如果委托对象实现了约束类中的业务(场景中的写论文writePagers()),业务将有自己完成即写论文的业务将会是大学生自己写而不会由写手来完成。
/**
* 委托的对象, 场景中的大学生
*/
class LowCollegeStudent(var writer: Paper) : Paper by writer{
override fun writePagers() {
print("论文自己完成")
}
}
属性委托:
委托属性一般是对重复使用的属性委托给代理类处理从而实现统一管理。例如:存储到SharedPreferences中的登录状态、ueserId、userNme等
属性委托的语法:
val/var <属性名>: <类型> by <表达式>:
属性的委托实际上是把属性的 get / set 委托给代理类处理,代理类只需要实现 getValue / setValue 方法即可,如果是val修饰的属性则只需要实现 getvalue方法,可以手动敲 getValue / setValue 方法,也可以通过实现Kotlin 标准库中声明了2个含所需operator方法的 ReadOnlyProperty / ReadWriteProperty 接口。其中 var修饰的属性 被委托类实现ReadWriteProperty 接口 , val 修饰的属性 被委托的类实现ReadOnlyProperty 接口即可。
class Example {
// 将属性p委托给 Delegate对象
var p: String by Delegate()
}
被委托对象
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.")
}
}
当需要获取属性p的时候,将会调用到Delegate的getValue方法。例如:
val e = Example()
Log.i(TAG,"打印属性p:"+e.p)
// 输出结果 Example@33a17727, thank you for delegating ‘p’ to me!
当我们对属性p赋值时候,将会调用到Delegate中的setValue方法,例如:
val e = Example()
e.p = "NEW"
Log.i(TAG,"打印属性p:"+e.p)
// 输出结果 NEW has been assigned to ‘p’ in Example@33a17727.
属性委托实际案例
我们项目中一般都有用户信息需要存储到SharedPreferences中的,比如 id name 等等,一般都是写一个SharedPreferencesUtil来对这些属性做存取操作。现在使用属性委托模式相对来说更加简单明了。
首先定义一个属性委托类:
class Preferenc<T>(var context: Context,val name:String,val default :T,val prefName :String ="default") : ReadWriteProperty<Any?,T>{
/**
* lazy 委托变量
*/
private val prefs by lazy {
context.getSharedPreferences(prefName,Context.MODE_PRIVATE)
}
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return findPreference(findProperName(property))
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
putPreference(findProperName(property),value)
}
/**
* 根据 default 来判断 数据类型
*/
private fun findPreference(key : String) : T{
return when(default){
is Long -> prefs.getLong(key,default)
is Int -> prefs.getInt(key,default)
is Boolean -> prefs.getBoolean(key,default)
is String -> prefs.getString(key,default)
else -> throw IllegalAccessException("Unsupported type.")
} as T
}
/**
* 查询名称
*/
private fun findProperName(property : KProperty<*>) : String = if (name.isEmpty()) property.name else name
/**
* 根据 value 类型来 保存数据
*/
private fun putPreference(key : String , value : T){
//定义 with 代表内部通过 this能够调用到 prefs.edit 返回的对象
with(prefs.edit()){
when(value){
is Long -> putLong(key,value)
is Int -> putInt(key,value)
is Boolean -> putBoolean(key ,value)
is String -> putString(key,value)
else -> throw IllegalAccessException("Unsupported type.")
}.apply()
}
}
}
再定义一个统一调用接口:
inline fun <reified R,T> R.pref(default : T) = Preferenc(App.getInstance(),"",default,R::class.jvmName)
最后就是需要存取的信息:
object UserInfo {
/**
* 属性委托
*/
var authID by pref(-1)
var username by pref("")
var password by pref("")
var token by pref("")
}
最后就是使用:
fun main(){
// 获取信息
val userId = UserInfo .authID
// 存取信息
UserInfo .authID = 1005
}