什么是观察者模式?
观察者模式属于行为设计模式,允许你定义一种订阅机制,可在事件发生时通知多个其他对象对该对象进行观察。
通过观察者模式解决问题:
拥有一些值得关注的状态的对象通常被称为目标,由于目标要将自身的状态改变通知给其他对象,我们也将目标称为发布者(published)。
所有希望关注发布者状态变化的其他对象被称为订阅者(subscribers)。
为发布者类添加订阅机制,让每个对象都能订阅或取消订阅发布者事件流,该机制包括:
- 一个用于存储订阅者对象引用的列表成员变量;
- 几个用于添加或删除该列表中订阅者的公有方法。
现在无论何时发生了重要的发布者事件,它都要遍历订阅者并调用其对象的特定通知方法。
实际应用中,可能会有很多个不同的订阅者类跟踪着同一个发布者类的事件,你不会希望发布者类和这些耦合在一起。
因此,所有订阅者都必须实现同样的接口,发布者仅通过该接口与订阅者交互。接口中必须声明通知方法及其参数,这样发布者在发出通知时还能传递一些上下文数据。
如果你的应用中有多个不同类型的发布者,且希望订阅者可兼容所有发布者,那么你甚至可以进一步让所有发布者遵循同样的接口。该接口仅需描述几个订阅方法即可。这样订阅者就能在不与具体发布者类耦合的情况下通过接口观察发布者的状态。
观察者模式结构
观察者模式适合的应用场景
当一个对象状态的改变需要改变其他对象,或实际对象是事先未知的或动态变化的时,可用观察者模式;
当你使用图形用户界面类时通常会遇到一个问题。比如,你创建了自定义按钮类并允许客户端在按钮中注入自定义代码,这样用户按下按钮时就会触发这些代码。
当应用中的一些对象必须观察其他对象时,可使用该模式。但仅能在有限时间内或特定情况下使用;
订阅列表是动态的,因此订阅者可随时加入或离开该列表。
实现方式
- 仔细检查你的业务逻辑,试着将其拆分为两部分:独立于其他代码的核心功能将作为发布者;其他代码则将转化为一组订阅类。
- 声明订阅者接口。该接口至少声明一个update方法。
- 声明发布者接口并定义一些接口来在列表中添加和删除订阅对象。发布者必须仅通过订阅者接口与他们交互。
- 确定存放实际订阅列表的位置并实现订阅方法。通常所有类型的发布者代码看上去都一样,因此将列表放置在直接拓展自发布者接口的抽象类中是显而易见的。具体发布者会扩展该类从而继承所有的订阅行为。但是在现有的类层次结构中应用该模式,则可以考虑使用组合的方式:将订阅逻辑放入一个独立的对象,然后让所有实际订阅者使用该对象。
- 创建具体发布者类。每次发布者发生了重要事件时都必须通知所有的订阅者。
- 在具体订阅者类中实现通知更新的方法。绝大多数订阅者需要一些与事件相关的上下文数据。这些数据可作为通知方法的参数来传递。但是还有另外一种选择。订阅者接收到通知后直接从通知中获取所有数据。在这种情况下,发布者必须通过更新方法将自身传递出去。另一种不太灵活的方式是通过构造函数将发布者与订阅者永久地联系起来。
- 客户端必须生成所需的全部订阅者,并在相应的发布者处完成注册工作。