定义
观察者模式,定义了对象之间一对多的依赖关系。当一个对象发生改变时,他的所有的依赖者都会收到通知
类图
- Subject:抽象主题,具有添加,移除和通知观察者的操作
- Observer: 抽象观察者,具有更新的操作
- ConcreteSubject:具体主题,Subject的实现者。除了实现Subject接口中方法以外,添了一些自定义的方法,比如更新温度的方法
- ConcreteOberver:具体的观察者。Observer的实现者,主要实现update方法。
接下来就简单看一下如何用代码实现
代码实现
首先是定义抽象主题接口
interface Subject{
void register(Observer o);
void unregister(Observer o);
void notifyAllObservers();
}
然后是抽象观察者接口
interface Observer {
void update(double temperature);
}
接下来就是具体主题的实现
class WetherData implements Subject{
ArrayList<Observer> list;
double temperature=0;
public WetherData() {
list=new ArrayList<>();
}
public void setTemperature(double temperature){
this.temperature=temperature;
this.notifyAllObservers();
}
@Override
public void register(Observer o) {
list.add(o);
}
@Override
public void unregister(Observer o) {
//list.indexOf()函数若是没有找到,则返回-1
int index=list.indexOf(o);
if(index>=0){
list.remove(index);
}
}
@Override
public void notifyAllObservers() {
for(Observer o:list){
o.update(temperature);
}
}
}
WetherData实现了SubJect接口,并实现了相关的方法。该类中使用list集合保存所有的已注册的观察者。当主题对象调用了setTemperature方法更新了温度时,就会通知所有的观察者温度已经发生改变了(即调用notifyAllObservers()方法)。
最后看一下观察者的具体实现
class ObserverA implements Observer{
@Override
public void update(double temperature) {
System.out.println("我是观察者A,我发现温度变化了,现在温度为" +temperature);
}
}
这了观察者A只是简单的输出了一下一句话。若是需要实现更加复杂的逻辑,只需修改相应的代码即可
优缺点
- 优点:解除了耦合,让耦合的双方都依赖于抽象,具体主题和具体观察者的变化不会影响对方;观察者模式支持广播通信;
- 缺点:如果被观察者有很多观察者,这是通知到所有的观察者会很耗时
java中内置的观察者模式
主要是java.util.Observer接口和java.util.Observable类,下面直接上代码
//具体主题
class ObserverTest extends Observable{
double temperature=0;
public void register(java.util.Observer o){
this.addObserver(o);
}
public void unregister(java.util.Observer o){
this.deleteObserver(o);
}
public void setTemperaure(double temperature){
this.temperature=temperature;
this.notifyAllObservers();
}
public double getTemperatrue(){
return temperature;
}
public void notifyAllObservers(){
this.setChanged();
this.notifyObservers();
}
}
//自定义了一个具体观察者,在这里只是简单的输出了一句话
class ObserverC implements java.util.Observer{
@Override
public void update(Observable o, Object arg) {
if(o instanceof ObserverTest ){
ObserverTest ot=(ObserverTest) o;
System.out.println("我是观察者c,我发现温度变化了,现在的温度是"+ot.getTemperatrue());
}
}
}
代码非常简单,但是有一个也需要注意的地方,在调用notifyObservers()方法之前,需要调用setChanged()。这样做的原因是setChanged方法会将changed变量的值修改为true,而notifyObservers方法的实现时,若是changed==false,会直接返回,不会通知其他的观察者。下面是具体的源码的实现
protected synchronized void setChanged() {
changed = true;
}
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}