观察者模式
Event-Subscriber、Listener、Observer
观察者模式也成作为发布订阅模式(Publish-Subscribe)
是一种订阅模式,能够在观察者和被观察者分离的情况下,将被观察者的事件通知给观察者;
在 Android 中也经常能看到和用到这种设计模式:
Application 中的
registerActivityLifecycleCallbacks允许对 Activity 生命周期变化事件的观察;对 View 设置
setOnClickListener是对点击事件的观察;LiveData、StateFlow、ShareFlow 这些容器允许订阅者观察到容器数据的变化;
....
优点:
遵守了 开闭原则,无需修改被观察者(发布者)代码就能引入新的观察者(订阅者)
允许观察者动态地订阅或取消接收请求
例子
对于观察者和被观察者,之间不能存在耦合;
举个例子,假设有一个花店,存在多个客户,当新进货鲜花的时候需要通知到对应的客户:
此时花店的商品是被观察者,客户是观察者,花店持有客户的引用,将客户和花店耦合在一起;
当以后还需要新增加新的角色时,比如管理员
Admin、经理Manager、员工等,都需要对 FlowerShop 这个类进行修改;这就违背了设计原则中的 开闭原则;
data class FlowerGoods(
val name: String,
val price: String
)
class Customer {
fun onSubscribe(goods: FlowerGoods) {
println("Now has new goods: $goods")
}
}
class FlowerShop(
private val customer: Customer
) {
private val allFlowerGoods = mutableListOf<FlowerGoods>()
// 进货新的鲜花
fun addNewFlowers(goods: FlowerGoods) {
allFlowerGoods.add(goods)
customer.onSubscribe(goods)
}
}
fun main() {
val shop = FlowerShop(Customer())
shop.addNewFlowers(
FlowerGoods("向日葵", "10.00元")
)
}使用观察者模式改善这种耦合关系:
抽离出一个接口,用于通知各种事件的发生;同时让花店无需知道对方具体是什么角色,这就将观察者和被观察者分离;
interface FlowGoodsChangeObserver { // 新增加时 fun onAdd(goods: FlowerGoods) // 移除商品时 fun onRemove(goods: FlowerGoods) // 有折扣时 fun onDiscount(goods: FlowerGoods) }花店使用一个列表存储这些观察者,提供方法注册观察者
class FlowerShop { private val allFlowerGoods = mutableListOf<FlowerGoods>() private val observers = mutableListOf<FlowerGoodsChangeObserver>() // 进货新的鲜花 fun addNewFlowers(goods: FlowerGoods) { allFlowerGoods.add(goods) observers.forEach { it.onAdd(goods) } } fun registerFlowerGoodsObserver(observer: FlowerGoodsChangeObserver) { this.observers.add(observer) } fun unregisterFlowerGoodsObserver(observer: FlowerGoodsChangeObserver) { this.observers.remove(observer) } }最后对于每一个不同的角色,只需要实现
FlowerGoodsChangeObserver接口即可;当新增角色时,就无需直接修改被观察者,而是直接实现对应的接口,这就遵守了 开闭原则
实现
对于观察者,可以实现一个接口 XxxObserver 来抽离出通用的方法:
interface XxxObserver {
fun onXxxAdd(...)
fun onXxxChange(...)
}对于被观察者,也能实现一个接口 XxxObserable 来抽离出实现观察者模式的方法:
interface XxxObserable {
fun registerXxxObserable(observer: XxxObserver)
fun unregisterXxxObserable(observer: XxxObserver)
}如果被观察着中存在多个事件需要被观察,那么可以将这些事件统一封装为一个 XxxEvent 类,交由观察者接口的一个方法进行处理:
Android 中的触摸事件
MotionEvent便是如此(不是指观察者模式,而是指将多种类型的事件封装为同一个类)
interface XxxObserver {
fun onEvent(event: XxxEvent)
}从上面例子的观察者模式中,被观察者持有观察者的是一个列表:
observer.forEach {
it.onAdd(goods)
}这是一个同步操作,只有上一个观察者处理完之后才能通知下一个观察者,如果当某一个观察者处理时间较久,就会导致后面的观察者收到事件通知比较晚;
此时可以考虑异步去通知;