观察者模式
需求分析
- 需求1,一个小孩哭了,爸爸喂,妈妈抱,狗叫…(一个对象有一定的反应,另外的几个不同的对象做出连锁反应)
- 需求2,可以根据小孩是哭还是笑还是…做出不同的反应。(能够根据不同的事件做出不同的反应)
- 需求3,爸爸可以把小孩的状态由哭变成笑。(能够调整事件源对象的状态) ----
- 需求4:小孩可以根据自己的不同状态,来决定自己是让爸爸处理还是妈妈处理。 — 结合命令模式
上面把观察者模式结合命令模式进行扩展。通知观察者,使用命令模式,使得观察者和被观察者解耦。
再加上责任链模式,可以动态的增加和减少功能。
JDK的观察者模式
- 更清晰的语义,状态改变的时候才需要通知其他人。
- 如果状态没有改变,不进行通知。
- 观察者自己也是一个发布面板 – doit(Event, Observer o) ;责任链的递归调用实现。观察者可以通知别的观察者进行观察。标准的责任链模式。
观察者模式分析
1. 定义
定义了对象之间的一对多依赖,这样依赖,当一个对象状态改变时,他的所有依赖都会收到通知并自动更新。
2. 优缺点
- 实现了观察者和被观察之间的解耦,也就是一个对象和他依赖对象之间的解耦。 (小孩类和爸爸,妈妈,小狗类都独立的)
- 可以动态增加功能,用于处理对观察者变化的反应。
3. 使用场景
- 对象之间存在依赖关系
- 对象之间的通信,结合责任链和命令模式
JDK内置的观察者模式
- 观察者,根据不同的主题的更新来决定自己是否更新,不能在改变主题的状态了, 否则会死循环。
- 具体的观察者绑定了某一个主题
- 观察者不能改变主题的状态,否则会陷入死循环。
- 被观察者,首先设置改变,其次通知所有的观察者。
改变之后,使用下面的代码进行通知所有的观察者。
setChange();
notifyAllObservers();
- Observable代码详解
1. 私有的属性: 是否改变,使用vector进行存储对象。
private boolean changed = false;
private Vector<Observer> obs;
2. 增加对象,是一个带锁的实现
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException(); // 首先判断是否为空
if (!obs.contains(o)) { // 其次判断是否已经有了,使用set会更快。
obs.addElement(o);
}
}
3. 删除对象,同样是一个带锁的实现
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
4. 使用对象是经典,解释了为什么需要设置一个change。 -- 为了提醒用户是否真的需要进行。
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray(); // 由于调用这个方法,非常的耗时,所以需要用户显示调用设置为true,才进行调用
clearChanged();
} // 没有等待所有的通知完成,而是复制了一份,然后就是线程私有的了,之后再慢慢进行处理,防止锁太长时间。
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
- 增删都加上锁
- 复制一份,让线程私有之后,再慢慢进行调用。