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