设计模式-观察者模式
Posted 双木青橙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-观察者模式相关的知识,希望对你有一定的参考价值。
1.定义
1.1抽象定义
- 报社的业务是出版报纸
- 向某家报社订阅报纸,只要他们有新报纸出版,就会向你送来,要是你是他们的订户,你就会一直收到他们的报纸。
- 当你不想再看报纸的时候,取消订阅,他们就会不再送报纸来。
相当于出版者+订阅者= 观察者模式,出版者改为为“主题”(subject),订阅者改称为“观察者”(Observer)。
1.2 标准定义
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都你会收到通知并自动更新。
观察者模式定义了一系列对象之间的一对多关系。当一个对象改变状态,其他依赖者都会收到通知。
1.3 观察者模式如何实现松耦合
当两个对象之间松耦合,它他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计。让主题和观察者之间松耦合。
关于观察者的一切,主题只知道观察者实现了某个接口(也就是Oberserver接口)。主题不需要知道观察者的具体类是谁,做了些什么或者其他任何细节。
任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者,主题不会受到任何影响。同时的,也可以在任何时候删除某些观察者。
有新类型的观察者出现时,主题的代码不需要修改。假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新的类里实现此观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了此观察者接口的对象。
我们可以解决一下地复用主题或者观察者。如果我们在其他地方需要使用主题或者观察者。可以轻易复用,因为二者并非紧耦合。
改变主题或者观察者其中一方,并不会影响另一方。因为两者是松耦合,所以只要是他们之间的接口仍被遵守,我们就可以自由地改变他们。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低
Observer接口与Observable类
Observer接口和Observable类是Java API内置的观察者模式,Observer是观察者,Observable是主题(subject)。值得注意的是:Observable并不是一个接口,而一个Java类。(当并不是一个好的方式,Java语言只允许继承一个父类,在大型项目中还是自己新建ObserverManager管理类或者实现一个接口来实现观察者模式。)
- Observable-主题类
/**
* 主题类
*/
public class Observable
private boolean changed = false;
private Vector<Observer> obs; //保存观察者对象
public Observable()
obs = new Vector<>();
/**
* 注册观察者,不允许同一观察者重复注册
*/
public synchronized void addObserver(Observer o)
if (o == null)
throw new NullPointerException();
if (!obs.contains(o))
obs.addElement(o);
/**
* 解注册观察者
*/
public synchronized void deleteObserver(Observer o)
obs.removeElement(o);
/**
* 当主题改变后(或者你想用通知观察者们)时,你一般会通过hasChanged标记主题已改变,然后通过此方法通知所有观察者,然后再通过
* clearChanged标记主题不再改变,直到下一次想要通知
* 此方法不带arg参数
*/
public void notifyObservers()
notifyObservers(null);
/**
* 见notifyObservers(null)方法
* 每个观察者的update方法被传入当前主题对象和arg参数依次调用
* @param arg Object类型,任意要传递给观察者参数
*/
public void notifyObservers(Object arg)
Object[] arrLocal;
synchronized (this)
/* 这是一个被synchronized 注解的同步方法块,用于同步获取最新的观察者列表。但是通知这些观察者实际上并不是同步的
* (不影响功能且有效避免阻塞)
* 最坏的情况是:
* (无论是否使用synchronized都可能存在这个问题,加了synchronized可以有效避免在实际通知过程中观察者被随意进出)
* 1)一个新添加的观察者会错过通知当通知已经在进步中时
* 2)一个刚解注册的观察者会被错误通知。
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
/**
* 清除所有观察者
*/
public synchronized void deleteObservers()
obs.removeAllElements();
/**
* 标记当前主题已经改变,注意,此方法一定要在调用notifyObservers之前
*/
protected synchronized void setChanged()
changed = true;
/**
* 清理主题Changed清理标记,常用于已经通知观察者后处理
*/
protected synchronized void clearChanged()
changed = false;
/**
* 获取当前主题是否已改变标记
*/
public synchronized boolean hasChanged()
return changed;
/**
* 获取观察者数量
*/
public synchronized int countObservers()
return obs.size();
- Observer接口-观察者
/**
* 一个类可以通过实现Observer接口,当它想被观察对象(主题)变化实时通知时。
*/
public interface Observer
/**
* 主题变化时,会调用notifyObservers通知观察者们,update方法在此时被调用
*
* @param o 主题
* @param arg notifyObservers传递过来的参数
*/
void update(Observable o, Object arg);
以上是关于设计模式-观察者模式的主要内容,如果未能解决你的问题,请参考以下文章
Java设计模式补充:回调模式事件监听器模式观察者模式(转)