观察者模式入门

基本概念

观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

观察者模式主要涉及四个关键对象:

  1. Subject被观察者:定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。

  2. Observer观察者:观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。

  3. ConcreteSubject具体的被观察者:定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

  4. ConcreteObserver具体的观察者:每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

观察者模式的两种类型:

  1. 推模型:主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。

  2. 拉模型:主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。

观察者模式的优点:

  1. 观察者和被观察者是抽象耦合的。
  2. 观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。

观察者模式的缺点:

  1. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
  2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

UML类图

代码示例

在现代购物体验中,一旦订单支付成功后,商户会通过各种渠道将支付结果及后续物流状态通知给用户,下面是在该场景下使用观察者模式的代码示例:

创建主题接口:

1
2
3
4
5
6
7
8
protocol ISuject {
//注册观察者
func addObserver(oberver:IObserver) -> Void
//移除观察者
func removeObserver(oberver:IObserver) -> Void
//通知观察者
func notifyObservers() -> Void
}

创建观察者接口:

1
2
3
protocol IObserver {
func update(result:Bool) -> Void
}

创建具体主题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class TicketsPurchaseResult{

private var observers:NSMutableArray = {
return NSMutableArray()
}()

var purchaseResult = false {
didSet{
self.notifyObservers()
}
}
}

extension TicketsPurchaseResult:ISuject{
func addObserver(oberver: IObserver) {
self.observers.add(oberver)
}

func removeObserver(oberver: IObserver) {
self.observers.remove(oberver)
}

func notifyObservers() {
for o in self.observers {
let observer = o as! IObserver
observer.update(result: purchaseResult)
}
}
}

创建具体观察者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class APNSNotice: IObserver {
func update(result: Bool) {
let resultDescription = (result ? "订票成功" : "订票失败")
print(resultDescription + ",发送推送通知用户")
}
}

class SMSNotice: IObserver {
func update(result: Bool) {
let resultDescription = (result ? "订票成功" : "订票失败")
print(resultDescription + ",发送短信通知用户")
}
}

class WeChatNotice: IObserver {
func update(result: Bool) {
let resultDescription = (result ? "订票成功" : "订票失败")
print(resultDescription + ",微信公众号通知用户")
}
}

class MailNotice: IObserver {
func update(result: Bool) {
let resultDescription = (result ? "订票成功" : "订票失败")
print(resultDescription + ",发送邮件通知用户")
}
}

客户端调用代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
订票结果(success/failure)通知:
1. app推送
2. 短信
3. 公众号
4. 邮件
*/

let tickets = TicketsPurchaseResult()

let apns = APNSNotice()
tickets.addObserver(oberver: apns)

let sms = SMSNotice()
tickets.addObserver(oberver: sms)

let wechat = WeChatNotice()
tickets.addObserver(oberver: wechat)

let mail = MailNotice()
tickets.addObserver(oberver: mail)

tickets.purchaseResult = true

tickets.removeObserver(oberver: apns)
tickets.removeObserver(oberver: sms)
tickets.removeObserver(oberver: wechat)
tickets.removeObserver(oberver: mail)

tickets.purchaseResult = false