Android開發中的基於觀察者模式實現的設計仍是不少的,好比rxjava、LiveData...常見的按鈕點擊事件html
觀察者模式定義可一對多的依賴關係,讓多個觀察者同時監聽某一個對象,當這個主體對象在狀態上發生變化時,會通知全部觀察者對象 ,使他們能自動更新本身,叫法也有不少,發佈-訂閱(Publish-Subscribe)、模型-視圖(Model-View)等等java
Java對於觀察者模式在java.util包中提供了Observer接口和Observable抽象類。註冊,刪除,通知觀察者等功能已內置。kotlin一樣支持使用Java中提供的觀察者模式bash
例如電商項目中的動態更新價格markdown
// 被觀察者 class PriceSubject : Observable() { // 定義一組觀察者對象 private val observers = mutableSetOf<Observer>() // 訂閱 fun subject(ob: Observer) { observers.add(ob) } // 解除訂閱 fun UnSubject(ob: Observer) { observers.remove(ob) } // 價格賦值 fun setPrice(price:Int ){ notify(price) } //更新數據 private fun <T : Any?> notify(msg: T) { for (ob in observers) { ob.update(this,msg) } } } // 觀察者 class PriceOb(private val channel:String):Observer{ override fun update(o: Observable?, price: Any?) { if (o is PriceSubject){ print("接收賦值-觀察者:$channel - 價格:$price\n") } } } class PriceOb1 :Observer by PriceOb("第三方") fun main(args: Array<String>) { PriceSubject().apply { // 訂閱 subject(PriceOb("自營")) subject(PriceOb1()) setPrice(100) } } 複製代碼
接收賦值-觀察者:自營 - 價格:100
接收賦值-觀察者:第三方 - 價格:100
複製代碼
kotlin中的委託屬性官方文檔 其中咱們須要的是app
可觀察屬性(observable properties): 監聽器會收到有關此屬性變動的通知ide
inline fun <T> observable(
initialValue: T,
crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit
): ReadWriteProperty<Any?, T>
複製代碼
如果咱們賦予價格屬性更多定義,咱們須要發佈者對外提供一個API接口而不是在實現Observer接口的類中區分不一樣的邏輯。oop
Delegates.observable()
中提供了表明委託屬性三個參數:元數據property: KProperty<*>
對象,新舊值。this
// 觀察者 interface PriceChangedListener { // 定義一系列事件 // fun onNormalPrice(price: Price) // 秒殺價 fun onSpikePrice(price: Price) // 預購價 fun onAdvancePrice(price: Price) // 會員價 fun onVIPPrice(price: Price) // } class PriceObserver : PriceChangedListener { override fun onNormalPrice(price: Price) { print("常規價${price.newPrice}") } override fun onSpikePrice(price: Price) { print("秒殺價${price.newPrice}") } override fun onAdvancePrice(price: Price) { print("預購價${price.newPrice}") } override fun onVIPPrice(price: Price) { print("會員價${price.newPrice}") } } data class Price(val newPrice: Int, //新價格 val oldPrice: Int, //舊價格 val type: Int, //價格屬性類型 val discount: Boolean //是否能抵用折扣 ) // 被觀察者 class PriceSubject { // 觀察者對象 private var listeners = mutableSetOf<PriceChangedListener>() fun subject(ob: PriceChangedListener) { listeners.add(ob) } fun unSubject(ob: PriceChangedListener) { listeners.remove(ob) } var price: Price by Delegates.observable(Price(0, 0, 0, false)) { property, oldValue, newValue -> listeners.forEach { when (newValue.type) { 0 -> it.onNormalPrice(newValue) 1 -> it.onSpikePrice(newValue) 2 -> it.onAdvancePrice(newValue) 3 -> it.onVIPPrice(newValue) } } } } fun main(args: Array<String>) { PriceSubject().apply { subject(PriceObserver()) price = Price(199, 0, 0, false) price = Price(99, 100, 3, false) } } 複製代碼
inline fun <T> vetoable(
initialValue: T,
crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean
): ReadWriteProperty<Any?, T>
複製代碼
在觀察者模式中,若是咱們不想被觀察的值被任意的修改,能夠利用Vetoable在新的值被賦值生效以前進行截獲,而後根據相關業務邏輯處理它。spa
var price: Price by Delegates.vetoable(Price(0, 0, 0, false)) { property, oldValue, newValue -> listeners.forEach { when (newValue.type) { 0 -> it.onNormalPrice(newValue) 1 -> it.onSpikePrice(newValue) 2 -> it.onAdvancePrice(newValue) 3 -> it.onVIPPrice(newValue) } } // 添加自定義規則 if (newValue.type==3&&newValue.oldPrice < newValue.newPrice) true else throw IllegalArgumentException("會員價格不合理") } 複製代碼