观察者模式:
定义对象是一种一对多的关系,当一这方的状态发生变化时,多的之方需要得到通知或更新.
观察者模式包含以下几个部份:
a.主题接口, 此接口是定义一之方的功能,此接口至少应该包含两个方法:
1.添加观察者
2.通知观察者
b.主题接口实现类
c.观察者接口,此接口定义多方的功能,至少应该包含以下功能
d.观察者实现类
观察者模式的UML图:
观察者与后继动作
对于观察者而言,除了监视被观察对象之外,更重要的是当发现被观察对象发生改变时应该采取什么样的动作,比如在学校教务系统中,HeadMaster一旦注意到有新的学生信息被保存成功时,就会调用sendMail方法发送一封邮件到校长的邮箱中,我们把诸如此类的动作称为后继动作。对于观察者而言,其后继动作可以分为两类:基于“推数据”的后继动作和基于“拉数据”的后继动作。
A.推数据
所谓“推数据”,即当被观察对象发生变化时,它将把相关的变化数据以参数的形式传给被观察者。比如,在学校教务系统的观察者模式中,我们使用的就是基于“推数据”的后继动作。当StudentBean的当前对象被保存到数据库后,该对象将作为参数被传入到update方法中,作为观察者的HeadMaster将从update方法的参数中得到需要的数据,形象一点来说,数据是由被观察者“推”给观察者的。
基于“推数据”的后继动作的优点在于观察者一方无需考虑数据是如何得到的,只需对得到的数据进行相应的处理即可。此时,观察者与被观察者之间几乎没有什么耦合。
基于“推数据”的后继动作的缺点在于观察者获得数据的形式是被动的,对于同一个观察对象而言,不同观察者想要获得的数据很有可能是不同的,但此时他们将不得不接受由参数传入的一些与自己没有关系的数据。比如,在学校教务系统中,校长可能只想得到学生的学历信息,而教务主任只想得到学生的交费信息,但他们将不得不接受一些与己无关的额外信息。此外,若方法update的参数发生变化也会对不同观察者的后继动作造成一些影响。
B.拉数据
所谓“拉数据”,即当被观察对象发生变化时,不是由被观察者把数据传给观察者,而是由观察者主动到被观察对象中来取得数据。形象一点来说,数据是由观察者主动到被观察者中来“拉” 的。当然,此时在被观察的对象或接口中需要提供一些方法来供观察者“拉”,同时在观察者对象中也需提供一个对被观察对象的引用的属性,由此也造成了观察者与被观察者之间一定程度的耦合。
观察者模式的效果有以下几个优点:
(1)观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体现察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
(2)观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
观察者模式有下面的一些缺点:
(1)如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
(2)如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察考模式时要特别注意这一点。
(3)如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
(4)虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。