携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第三十天,点击查看活动详情
重学设计模式之观察者/订阅模式(Kotlin)
前言
观察者模式(Observer)又称发布-订阅模式(Publish-Subscribe:Pub/Sub)。它是一种通知机制,让发送通知的一方(被观察方)和接收通知的一方(观察者)能彼此分离,互不影响。
适用场景
-
一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用
-
一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度
-
一个对象必须通知其他对象,而并不知道这些对象是谁
-
需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制
观察者/订阅模式的角色及职责
- 抽象主题(Subject):
它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
- 具体主题(Concrete Subject):
将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
- 抽象观察者(Observer):
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体观察者(Concrete Observer):
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调
实例
我们就以订阅公众号为例,当用户订阅公众号的,当公众号有更新通知订阅的用户:
- 创建抽象观察者
Observer:
interface Observer {
//更新
fun update()
}
- 创建抽象主题
Subject:
open class Subject {
//观察者数组
private val oVector: Vector<Observer> = Vector()
//增加一个观察者
fun addObserver(observer: Observer?) {
println("用户订阅公众号")
oVector.add(observer)
}
//删除一个观察者
fun deleteObserver(observer: Observer?) {
println("用户取消订阅公众号")
oVector.remove(observer)
}
//通知所有观察者
fun notifyObserver() {
for (observer in oVector) {
observer.update()
}
}
}
- 创建具体主题,这里就是公众号
WeChatAccount:
//公众号
class WeChatAccount() : Subject() {
//开始上传文章
fun doSomething() {
println("开始上传文章了!!! ")
super.notifyObserver();
}
}
- 创建具体观察者,这里就是用户
User:
//用户
class User() :Observer{
override fun update() {
println("我收到更新了,我要开始看文章,点赞了!!!")
}
}
- 创建客户端:
class Client(){
fun main() {
//创建公众号
val subject = WeChatAccount()
//创建用户
val observer: Observer = User()
//用户订阅公众号
subject.addObserver(observer)
//公众号更新文章
subject.doSomething()
//用户取消订阅
subject.deleteObserver(observer)
//公众号更新文章
subject.doSomething()
}
}
输出:
用户订阅公众号
开始上传文章了!!!
我收到更新了,我要开始看文章,点赞了!!!
用户取消订阅公众号
开始上传文章了!!!
观察者/订阅模式优缺点
优点:
-
观察者和被观察者是抽象耦合的
-
建立一套触发机制
缺点:
-
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
-
如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
-
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化