观察者模式中通常有两个基本的概念主题:观察者和被观察者。当被观察者状态发生改变时,需要通知相应的观察者,当然,每个被观察者所对应的观察者可能不知一个,他们之间是1:n的关系。用专业一点的术语对观察者模式的描述为:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化。
观察者模式说明:
观察者与被观察者成员变量关系(即观察者需要是被观察者的某种成员变量)或被观察者可以有指向观察者的引用;当被观察者某种方法执行或者状态改变时,其内部实现中调用了观察者的相关方法。
(一个是能够找的到观察者,为调用观察者的函数提供指针引用;一个是 能够执行相关观察者对应的函数调用 具有权限和对应的参数条件)
观察者模式的一般实现方式如下:
1.定义观察者所具有的共同的接口:
1interfaceObserver {2publicvoidupdate();3}
2.定义两个观察者:
1classObserverAimplementsObserver {@Overridepublicvoidupdate() {System.out.println("ObserverA has received!");}}
1classObserverBimplementsObserver {23@Override4publicvoidupdate() {5System.out.println("ObserverB has received!");6}7}
3.定义被观察者所具有的抽象父类:
1abstractclassObservable {23privateVector
vector =newVector();45publicvoidadd(Observer observer) {6vector.add(observer);7}89publicvoiddel(Observer observer) {10vector.remove(observer);11}1213publicvoidnotifyObservers() {14Enumeration enumo =vector.elements();15while(enumo.hasMoreElements()) {16enumo.nextElement().update();17}18}1920publicvoidoperation() {2122}23}
4.定义具体的被观察者:
classConcretObservableextendsObservable{
@Overridepublicvoidoperation() {
System.out.println("update self!");
notifyObservers();
}
}
5.测试:
1publicclassObserverTest {23publicstaticvoidmain(String[] args) {4Observable sub =newConcretObservable();5sub.add(newObserverA());6sub.add(newObserverB());78sub.operation();9}1011}
初始化时,被观察者 如果申明对象类型为observable(抽象类型) 则不能调用自己声明实现的方法,只能调用父类(抽象类observable声明的接口,不管有没有实现(实现类中会实现抽象方法))
建立 观察者与被观察者的成员变量关系
被观察者的某一动作触发了 观察者的改变 -- 即在被观察者的方法实现中调用 观察者的相关部分的方法操作,同时为了保障 被观察者 可以同时被 多个观察者监测, 观察者与被观察者本身应该存在一定的关联关系,可能是成员变量关系,也可能是方法调用关系
抽象类 与接口的区别就是可以实现已声明的方法,在子类继承时,可重写也可直接调用当前抽象类的 已实现方法。
抽象类里的函数只声明不实现的话,需要添加关键字abstract,子类继承抽象类时需要实现该抽象类。
在抽象类的notifybserves() 方法中 执行update操作时,每个对象元素都实现了observer接口,同时,父类引用指向子类对象,因此,执行的update方法不尽相同, 这就是运行时多态。
观察者模式的应用场景:
1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
观察者模式的优点:
1、 Subject和Observer之间是松偶合的,分别可以各自独立改变。
2、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
观察者模式的效果有以下的优点:第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。观察者模式有下面的缺点:第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
观察者模式的效果有以下的优点:
第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。
第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知,
观察者模式有下面的缺点:
第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
观察者模式的应用场景:
1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
场景描述:
* 哈票以购票为核心业务(此模式不限于该业务),但围绕购票会产生不同的其他逻辑,如:
* 1、购票后记录文本日志
* 2、购票后记录数据库日志
* 3、购票后发送短信
* 4、购票送抵扣卷、兑换卷、积分
* 5、其他各类活动等
*
* 传统解决方案:
* 在购票逻辑等类内部增加相关代码,完成各种逻辑。
*
* 存在问题:
* 1、一旦某个业务逻辑发生改变,如购票业务中增加其他业务逻辑,需要修改购票核心文件、甚至购票流程。
* 2、日积月累后,文件冗长,导致后续维护困难。
*
* 存在问题原因主要是程序的"紧密耦合",使用观察模式将目前的业务逻辑优化成"松耦合",达到易维护、易修改的目的,
* 同时也符合面向接口编程的思想。
*
* 观察者模式典型实现方式:
* 1、定义2个接口:观察者(通知)接口、被观察者(主题)接口
* 2、定义2个类,观察者对象实现观察者接口、主题类实现被观者接口
* 3、主题类注册自己需要通知的观察者
* 4、主题类某个业务逻辑发生时通知观察者对象,每个观察者执行自己的业务逻辑。