一、什么是观察者模式
定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生改变时会通知所有观察者对象,使他们能够自动更新自己。
二、观察者模式的特点
将一个系统分割成一系列相互协作的类,有一个很不好的副作用,那就是需要维护相关对象之间的一致性,如果为了维持一致性而是各类紧密耦合是大家都不希望看到的,这会给维护和扩展,重用带来不便。
什么时候考虑使用观察者设计模式呢,当一个对象的改变需要改变其他对象时,而且它比不知道有多少对象有待改变时。就可以使用观察者模式了。
观察者模式所做的工作就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不影响另一边的变化。
三、观察者模式的设计原则
为了交互对象之间的松耦合设计而努力。
它提供了一种对象设计,让主题和观察者之间松耦合。
关于观察者的一切,主题只知道观察者实现了某个接口,主题不需要知道观察者的具体类是谁,做了些什么或其他任何细节。
任何时候都可以增加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以就可以随时增加观察者。在实际的运行中,可以用新的观察者取代现有的观察者,主题不会受到任何影响。同样,也可以在任何时候删除某些观察者。
有新类型的观察者出现时,主题的代码不需要修改,所要做的就是在新的类里实现此观察者接口,然后注册为观察者即可,主题不在乎别的,他只会发送通知给所有实现了观察者接口的对象。
可以独立的复用主题或观察者,如果需要在其他地方使用主题或观察者,也可以轻易复用,因为二者并非紧耦合。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到了最低。
四、观察者模式的设计要点
1.要明确谁是主题,谁是观察者,主题与观察者是一对多的关系,一个被观察者可以有多个监听对象。
2.主题至少需要有三个方法:添加监听者、移除监听者、通知Observer的方法。观察者至少要有一个方法:更新方法,即更新当前的内容,做出相应的处理。
推模型和拉模型
监听模式根据其侧重的功能还可以分为推模型和拉模型。
推模型:被观察者对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
如某App的服务要在凌晨1:00开始进行维护,1:00—2:00所有服务会暂停,这里你就需要向所有的App客户端推送完整的通知消息:“本服务将在凌晨1:00开始进行维护,1:00—2:00所有服务会暂停,感谢您的理解和支持!”不管用户想不想知道,也不管用户会不会在这期间访问App,消息都需要被准确无误地发送到。这就是典型的推模型的应用。
拉模型:被观察者在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到被观察者对象中获取,相当于观察者从被观察者对象中拉数据。
如某App有新的版本推出,需要发送一个版本升级的通知消息,而这个通知消息只会简单地列出版本号和下载地址,如果需要升级App,还需要调用下载接口去下载安装包完成升级。这其实也可以理解成拉模型。
五、观察者模式的实战应用
在互联网广泛普及和快速发展的时代,信息安全被越来越多的人重视,其中账户安全是信息安全最重要的一个部分。很多网站都会有一个账号异常登录检测和诊断机制。当账户异常登录时,会以短信或邮件的方式将登录信息(登录的时间、地区、IP地址等)发送给已经绑定的手机或邮箱。
Java.util包内包含最基本的Observer接口和Observable类,这和Subject接口与Observer接口很相似,Observer接口和Observable类,使用上更方便,因为许多功能已经事先准备好了。你甚至可以使用推(push)或拉(pull)的方式传递数据。
在JDK中,并非只有在java.util中才能找到观察者模式,其实在JavaBeans和Swing中也都实现了观察者模式。
六、小结
1.观察者模式定义了对象之间一对多的关系。
2.主题用一个共同的接口来更新观察者
3.观察者和主题之间用松耦合方式结合
4.使用观察者模式时,你可以从被观察者处推(push)或拉(pull)数据
5.有多个观察者时,不可以依赖特定的通知次序
6.Java有多种观察者模式的实现,包括了通用的Java.util.Observable
7.Swing大量使用了观察者模式。许多GUI框架也是如此。
8.此模式被应用在许多地方,例如JavaBeans,RIM