观察者模式
是什么?
观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。
怎么做?
在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖他的对象都会收到通知,并自动更新。
- 区分观察者和可观察者。
- 定义 Observable、Observer 可观察者和观察者的接口协议。
- 具体可观察者实现 Observable 协议。添加、移除、通知观察者等接口协议。
- 具体观察者实现 Observer 协议。统一的数据更新通知接口。
遵守原则?
- 封装变化。
- 多用组合,少用继承。
- 针对接口编程,不针对实现编程。
- 为交互对象之间的松耦合设计而努力。
第一步,区分可观察者和观察者:
拿招聘做比喻,招聘网站是可观察者,你就是观察者。因为你成为网站的会员并填写完详细信息后就相当于注册到观察者队列中,等网站有适合你的职位时就会发出通知给你。 因为有千千万万的你,而这家招聘网站是唯一的,所以是一对多的关系(其他招聘网站是其他的可观察者)。
第二步,抽象代码:
protocol Observable {
func registerObserver(obj: NewspaperObserver)
func removeObserver(obj: NewspaperObserver)
func notifyObservers()
}
protocol Observer {
func updateData(pages: Int, price: Float)
}
// 可观察者实现 Observable 协议
class NewspaperData: NSObject, Observable {
func registerObserver(obj: NewspaperObserver) -> Void { }
func removeObserver(obj: NewspaperObserver) -> Void { }
func notifyObservers() -> Void { }
}
// 观察者A实现 Observer 协议
class NewspaperReaderA: NSObject, Observer {
func updateData(pages: Int, price: Float) { }
func display() { }
}
第三步,组合调用:
可观察者和观察者之间角色是可以多重的。
1.0 可观察者、观察者的协议
// Observable
protocol NewspaperSubject {
func registerObserver(obj: NewspaperObserver)
func removeObserver(obj: NewspaperObserver)
func notifyObservers()
}
// Observer
protocol NewspaperObserver {
func updateData(pages: Int, price: Float)
}
// 观察者的抽象协议,仅仅是为了针对接口编程,不针对实现编程。
protocol NewspaperDisplayElement {
func display()
}
2.0 被观察者实现
class NewspaperData: NSObject, NewspaperSubject {
var pages: Int = 0 {
didSet {
self.notifyObservers()
}
}
var price: Float = 0.0 {
didSet {
self.notifyObservers()
}
}
private var observersArrayM: Array<NewspaperObserver> = Array()
func registerObserver(obj: NewspaperObserver) -> Void {
observersArrayM.append(obj)
}
func removeObserver(obj: NewspaperObserver) -> Void {
var removeIndex = -1
for (index, observer) in observersArrayM.enumerated() {
let obj1 = obj as AnyObject
let obj2 = observer as AnyObject
if obj1.isEqual(obj2) {
removeIndex = index
}
}
if removeIndex != -1 {
observersArrayM.remove(at: removeIndex)
}
}
func notifyObservers() -> Void {
for observier in observersArrayM {
observier.updateData(pages: self.pages, price: self.price)
}
}
}
** 3.0 观察者的实现**
class NewspaperReaderA: NSObject, NewspaperObserver, NewspaperDisplayElement {
private var pages: Int = 0
private var price: Float = 0.0
func updateData(pages: Int, price: Float) {
self.pages = pages
self.price = price
self.display()
}
func display() {
print("\(self.className) pages:\(self.pages) price:\(self.price)")
}
}
class NewspaperReaderB: NSObject, NewspaperDisplayElement, NewspaperObserver {
private var pages: Int = 0
private var price: Float = 0.0
func updateData(pages: Int, price: Float) {
self.pages = pages
self.price = price
self.display()
}
func display() {
print("\(self.className) pages:\(self.pages) price:\(self.price)")
}
}
5.0 测试代码
let data = NewspaperData()
let readerA = NewspaperReaderA()
let readerB = NewspaperReaderB()
// 添加观察者
data.registerObserver(obj: readerA)
data.registerObserver(obj: readerB)
data.pages = 8
print("----------------------")
// 移除观察者
data.removeObserver(obj: readerA)
data.price = 199.8
打印结果:
NewspaperReaderA pages:8 price:0.0
NewspaperReaderB pages:8 price:0.0
----------------------
NewspaperReaderB pages:8 price:199.8
观察者的优点
- 当抽象个体有两个互相依赖的层面时。封装这些层面在单独的对象内将可允许程序员单独地去变更与重复使用这些对象,而不会产生两者之间交互的问题。
- 当其中一个对象的变更会影响其他对象,却又不知道多少对象必须被同时变更时。
- 当对象应该有能力通知其他对象,又不应该知道其他对象的实做细节时。
缺点
- 有多个观察者时,不可以依赖特定的通知次序。
- 有些时候优点反过来就是缺点了。