当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。
比如:当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为模式。
介绍
意图: 定义对象之间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。
主要解决: 一个对象的状态改变给其它对象通知的问题, 而且要考虑到易用和低耦合,保证高度的协作。
何时使用: 一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决: 使用面向对象技术,可以将这种依赖关系弱化。
关键代码: 在抽象类里有一个ArrayList存放观察者们。
应用实例:
- 拍卖的时候,拍卖师观察最高标价,然后通知给其它竞价者竞价
- 西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个就是观察者,他观察菩萨洒水这个动作。(这个不熟)
优点:
- 观察者和被观察者是抽象耦合的。
- 建立一套触发机制。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都会通知到会花费很多时间
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发他们之间进行循环调用,可能导致系统崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
- 有多个子类共有的方法,且逻辑相同。
- 重要的、复杂的方法,可以考虑作为模板方法。
注意事项:
- JAVA中已经有了观察者模式的支持类。
- 避免循环引用。
- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
实现
可观察者要如何送出通知?
首先需要扩展java.util.Observable接口产生“可观察者”类,然后需要两个步骤
- 先调用setChanged()方法,标记状态已经被改变的事实。
- 然后调用两种notifyObservers()方法中的一个:
notifyObservers()或者notifyObservers(Object arg)当接收通知时,可以传递任何的数据对象(arg)给每一个观察者。
推拉模型比较
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递 给观察者,让观察者自己去按需要取值。
推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数(Object),可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;
而拉模型就不会造成这样的情况,因为拉模型下, update()方法的参数是主题对象本身(Observable),这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。