今天,我们来分享行为型模式的另外一个成员:观察者模式。
观察者是一种行为型模式,它定义了对象之间的一种一对多的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都会得到通知并自动更新。观察者模式也叫发布-订阅模式(Publish-Subscribe)
意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变的时候,所有依赖于它的对象都得到通知并被自动更新。
结构
观察者模式基本的结构如下图所示:
在观察者模式中,通常包含两个主要角色:观察者和被观察者。被观察者(也称为主题)维护了一系列观察者对象,并在自身状态发生改变时通知这些观察者。观察者则实现了一个更新接口,以便被被观察者通知时能够及时进行相应的更新。
主要包括如下几个部分:
Subject(目标)
Observer(观察者)
ConcreteObserver(具体观察者)
JDK提供了java.util.Observer和java.util.Observable可以实现观察者模式(注:在Java是9中已经被标注为过期 )。
java.util.Observable
从上述Observable的截图可以看出,Observerable维护一个changed状态和需要通知的订阅者列表。
当状态改变的时候,会依次通知各个订阅者。
另外,还有添加订阅者、删除订阅者等方法,如:
java.util.Observer
Observer接口就一个update方法,用于获取来自主题的消息更新。
接下来,我们先使用JDK内置的Observer完成一个观察者模式的示例。
使用JDK内置的Observer示例
一个项目完成了,大家一起去聚餐嗨皮。看着时间还早,Eric提议说要不我们再去唱会歌吧。大家都可以开心说“好啊”。Eric说我先去KTV看下,具体房间号定好,我再通知大家。
就这样一个场景,很适合观察者模式,借助JDK内置的Observer和Observable,我们来看下如何完成。
KtvOrder - 主题(发布者)
KtvParticipant - 被观察者(订阅者)
客户端Client
输出结果:
这样,一个使用JDK内置的Observer示例就完成了。
示例二、事件源和事件监听器
其实,像上述这样的示例,我们可以认为是事件处理。可以包含事件源和事件监听器。
事件源负责产生事件,事件监听器则负责监听事件并进行相应的处理。
事件源
事件监听器
客户端Client
运行结果
一个简单的事件处理就完成了。
像此类事件监听处理,想必很多读者想到了Guava的EventBus以及Spring的ApplicationEvent,有兴趣的读者也可以看看这块的源代码。
观察者模式的应用非常广泛,例如在GUI编程中,当一个用户界面元素的状态改变时,可以使用观察者模式来通知其他相关的用户界面元素进行相应的更新。在事件驱动编程中,观察者模式也是一个非常有用的模式,可以实现事件的订阅和发布,从而使得事件的产生和处理分离开来。
观察者模式中的角色
通常包含两个主要角色:观察者和被观察者。
被观察者(也称为主题)维护了一系列观察者对象,并在自身状态发生改变时通知这些观察者。
观察者则实现了一个更新接口,以便被被观察者通知时能够及时进行相应的更新。
一般观察者模式编写步骤
定义主题(Subject)接口:
主题是被观察者对象,通过提供注册观察者、删除观察者、通知观察者等方法。
实现主题类:
主题类应该继承主题接口,并提供一些额外的方法,例如修改状态并通知观察者。
定义观察者(Observer)接口:
观察者接口通常只包含一个方法,即更新方法。
实现观察者类:
在主题中添加观察者:
主题类需要维护一个观察者列表,可以在注册观察者和删除观察者方法中添加和移除观察者。
在主题状态发生变化时通知观察者:
主题类在状态发生变化时,需要遍历观察者列表,并调用每个观察者的更新message方法。
客户端Client:
创建一个主题对象和多个观察者对象,并将观察者注册到主题对象中
输出结果
如果有多主题的话,可以使用ConcurrentHashMap来存储。
比如:
定义支持多主题接口和具体实现
有兴趣的读者可以自己编写试试。
容易混淆的模式
观察者模式容易与以下两种模式混淆:
发布-订阅模式(Publish-Subscribe Pattern):
在观察者模式中,主题对象和观察者对象是紧密耦合的,主题对象维护一个观察者列表,并通知它们状态的改变。
而在发布-订阅模式中,消息的发送方(发布者)不需要知道消息的接收方(订阅者)是谁,消息会经过一个中心化的调度器来传递。
装饰者模式(Decorator Pattern):
观察者模式强调的是主题对象与观察者对象的松耦合关系,而装饰者模式强调的是在不改变原有对象接口的情况下增加新的行为。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。