Android设计模式(三) 观察者模式

Android开发中的基于观察者模式实现的设计还是很多的,比如rxjava、LiveData...常见的按钮点击事件

  • Button ---> 被观察者
  • OnClickListener ---> 观察者
  • setOnClickListener() ---> 订阅
  • OnClick() ---> 事件

观察者模式定义可一对多的依赖关系,让多个观察者同时监听某一个对象,当这个主体对象在状态上发生变化时,会通知所有观察者对象 ,使他们能自动更新自己,叫法也有很多,发布-订阅(Publish-Subscribe)、模型-视图(Model-View)等等

Java对于观察者模式在java.util包中提供了Observer接口和Observable抽象类。注册,删除,通知观察者等功能已内置。kotlin同样支持使用Java中提供的观察者模式

例如电商项目中的动态更新价格

// 被观察者
class PriceSubject : Observable() {
    // 定义一组观察者对象
    private val observers = mutableSetOf()
    // 订阅
    fun subject(ob: Observer) {
        observers.add(ob)
    }
    // 解除订阅
    fun UnSubject(ob: Observer) {
        observers.remove(ob)
    }
    // 价格赋值
    fun setPrice(price:Int ){
            notify(price)
    }
    //更新数据
    private fun  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) {
    PriceSubject().apply {
         // 订阅
        subject(PriceOb("自营"))
        subject(PriceOb1())
        setPrice(100)
    }
}
接收赋值-观察者:自营 - 价格:100
接收赋值-观察者:第三方 - 价格:100

委托属性

kotlin中的委托属性官方文档
其中我们需要的是

可观察属性(observable properties): 监听器会收到有关此属性变更的通知

inline fun  observable(
    initialValue: T,
    crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit
): ReadWriteProperty

若是我们赋予价格属性更多定义,我们需要发布者对外提供一个API接口而不是在实现Observer接口的类中区分不同的逻辑。

Delegates.observable()中提供了代表委托属性三个参数:元数据property: KProperty<*>对象,新旧值。

// 观察者
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()

    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) {
    PriceSubject().apply {
        subject(PriceObserver())
        price = Price(199, 0, 0, false)
        price = Price(99, 100, 3, false)
    }
}

Vetoable

inline fun  vetoable(
    initialValue: T,
    crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean
): ReadWriteProperty

在观察者模式中,如果我们不想被观察的值被任意的修改,可以利用Vetoable在新的值被赋值生效之前进行截获,然后根据相关业务逻辑处理它。

   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("会员价格不合理")

    }

你可能感兴趣的:(android,kotlin,设计模式)