3.kotlin筆記_代理

1. 代理模式

    interface Base {
        fun printMessage()
        fun printMessageLine()
    }

    class BaseImpl(val x: Int) : Base {
        override fun printMessage() { print(x) }
        override fun printMessageLine() { println(x) }
    }

    class Derived(b: Base) : Base by b {
        override fun printMessage() { print("abc") }
    }

    @Test
    fun test17() {
        val b = BaseImpl(10)
        Derived(b).printMessage()//執行自身類裏覆寫的方法 abc
        Derived(b).printMessageLine()//執行代理類裏已有的方法 10
    }

需要注意的是,這種覆寫的成員只能由自身訪問,其代理對象是訪問不到的,代理對象只能訪問它自身的成員:

    interface Base {
        val message: String
        fun print()
    }

    class BaseImpl(val x: Int) : Base {
        override val message = "BaseImpl: x = $x"
        override fun print() { println(message) }
    }

    class Derived(b: Base) : Base by b {
        // This property is not accessed from b's implementation of `print`
        override val message = "Message of Derived"
    }

    @Test
    fun test18() {
        val b = BaseImpl(10)
        val derived = Derived(b)
        derived.print()
        println(derived.message)
    }

執行結果:
BaseImpl: x = 10
Message of Derived

2. 屬性委託

    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.")
        }
    }

    class Example {
        var p: String by Delegate()
    }

    @Test
    fun test19(){
        val e = Example()
        e.p = "aaa"
        println(e.p)
    }

執行結果:
aaa has been assigned to ‘p’ in com.aislli.ktdemo.KotlinTest3Example@6f75e721.com.aislli.ktdemo.KotlinTest3 Example@6f75e721, thank you for delegating ‘p’ to me!

3. kotlin提供了幾種常用的標準代理方式

3.1 lazy

val lazyValue: String by lazy {
    println("first!")
    "Hello"
}

@Test
fun test20() {
    println(lazyValue)
    println(lazyValue)
}

執行結果:
first!
Hello
Hello
只在第一次獲取該字段的值時,會進行lazy{}裏的一系列處理運算,並通過lamdba形式返回結果初始化該字段的值並存儲起來,之後再獲取該字段值時就不會再運算了,而是直接返回之前存儲的值。

3.2 observable

class User {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        println("$old -> $new")
    }
}

fun test16() {
    val user = User()
    user.name = "first"
    user.name = "second"
}

執行結果:
-> first
first -> second
三個參數分別代表:
prop:被賦值的屬性
old:舊值
new:新值
如果要禁止修改舊值操作,可以用vetoable:

    class User {
        var age: Int by Delegates.vetoable(0) {
            property, oldValue, newValue ->
            println("${property.name}:$oldValue:$newValue")
            false
        }
    }
    @Test
    fun test16() {
        val user = User()

        user.age = 1
        user.age = 2
    }

執行結果:
age:0:1
age:0:2

3.3 map

    class User(map: Map<String, Any?>) {
        val name: String by map
        val age: Int     by map
    }

    @Test
    fun test21() {
        val user = User(mapOf(
                "name" to "John Doe",
                "age"  to 25
        ))
        println(user.name) // Prints "John Doe"
        println(user.age)  // Prints 25
    }

用map的功能來代理JSON解析等處理中的賦值操作,例如上例中map代理相當於做了類似下面的事情:

    var name: String = map["name"] as String
    var age: Int = map["age"] as Int

3.4實例 ####

使用代理對SharedPreferences工具類進行封裝:

import android.content.Context
import android.content.SharedPreferences
import kotlin.reflect.KProperty

/**
 * Created by Aislli on 2018/8/9 0009.
 */
class SP<T>(val name: String, val default: T) {
    private val sp: SharedPreferences by lazy {
        App.instance.getSharedPreferences(name, Context.MODE_PRIVATE)
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return getSP(name, default)
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        putSP(name, value)
    }

    private fun putSP(key: String, value: T) = with(sp.edit()) {
        when (value) {
            is String -> putString(key, value)
            is Int -> putInt(key, value)
            is Long -> putLong(key, value)
            is Boolean -> putBoolean(key, value)
            is Float -> putFloat(key, value)
            else -> throw IllegalArgumentException("Cant not save this type")
        }.apply()
    }

    @Suppress("UNCHECKED_CAST")
    private fun getSP(key: String, default: T): T = with(sp) {
        val res: Any = when (default) {
            is String -> getString(key, default)
            is Int -> getInt(key, default)
            is Long -> getLong(key, default)
            is Boolean -> getBoolean(key, default)
            is Float -> getFloat(key, default)
            else -> throw IllegalArgumentException("Cant not get this type")
        }
        return res as T
    }

}

App.java

class App : Application() {
    companion object {
        lateinit var instance: App
    }

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}

使用方式:

class MainActivity : AppCompatActivity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            var openType by SP<Boolean>("open_type",false)
            toast("now the opentype is $openType")//初始值爲false
            rg_install.setOnCheckedChangeListener { p0, p1 ->
                when (p1) {
                    R.id.radioButton-> openType = true//自動調用了sharedPreferences.edit().putBoolean("open_type",false)
                    R.id.radioButton2-> openType = false
                }
                toast("now the opentype is $openType")//自動調用了sharedPreferences.getBoolean("open_type",false)
            }

        }
    }

源碼

發佈了48 篇原創文章 · 獲贊 53 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章