观察者模式又叫做发布-订阅(Publish/Subscribe)模式,在设计模式这本书中是这样定义的:
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。(DP)
下面让我们来看一下观察者模式的结构图:
主题(Subject)类:该抽象类把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;
具体主题实现类(ConcreteSubject):将有关状态存入具体观察着对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知;
抽象观察者(Observer)类:为所有的具体观察者定义一个接口,在得到通知时更新自己;
具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调
而Java的java.util包里面提供了一个Observable类以及一个Observer接口,构成Java语言对观察者模式的支持。
Observable类:
被观察者继承父类Observable实现被观察者,下面讲解一下里面的几个方法:
1、addObserver(Observer o) 如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者,参数则为要添加的观察者
2、deleteObserver(Observer o)从对象的观察者集合中删除某个观察者
3、setChanged()标记此 Observable 对象为已改变的对象,当调用该方法以后,hasChanged该方法的结果将返回true,调用下面的notifyObservers方法以后,则hasChanged将返回false
4、notifyObservers()和notifyObservers(Object arg )如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
该方法中的参数arg为Observer类中update方法中需要的参数,每个观察者都有其 update 方法,其调用参数有两个:observable 对象和 arg 参数。
下面写了一个该设计模式的小例子:
一个加热器还有一个显示器,当加热器的温度改变了以后,会发出通知显示器,使其更新,而显示器有一个update的方法,显示改变以后的当前温度。
import java.util.Observable;
public class Heater extends Observable {
private int temperature;
public int getTemperature() {
return temperature;
}
public void setTemperature(int temperature) {
this.temperature = temperature;
}
public void boilWater() {
for (int i = 90; i < 110; i++) {
temperature = i;
setChanged();
notifyObservers("这是参数");
}
}
}
import java.util.Observable;
import java.util.Observer;
public class Display implements Observer {
private String status;
public Display() {
status = "加热中";
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public void update(Observable arg0, Object arg1) {
displayTemperature(((Heater) arg0).getTemperature());
System.out.println(arg1.toString());
}
private void displayTemperature(int temperature) {
if (temperature > 100) {
this.setStatus("沸腾");
}
System.out.println("状态: " + status + " 现在温度: "
+ temperature);
}
}
public class OberverDesign {
public static void main(String[] args) {
Heater heater = new Heater();
Display display = new Display();
heater.addObserver(display);
heater.boilWater();
}
}
执行结果如下:
状态: 加热中 现在温度: 90
这是参数
状态: 加热中 现在温度: 91
这是参数
状态: 加热中 现在温度: 92
这是参数
状态: 加热中 现在温度: 93
这是参数
状态: 加热中 现在温度: 94
这是参数
状态: 加热中 现在温度: 95
这是参数
状态: 加热中 现在温度: 96
这是参数
状态: 加热中 现在温度: 97
这是参数
状态: 加热中 现在温度: 98
这是参数
状态: 加热中 现在温度: 99
这是参数
状态: 加热中 现在温度: 100
这是参数
状态: 沸腾 现在温度: 101
这是参数
状态: 沸腾 现在温度: 102
这是参数
状态: 沸腾 现在温度: 103
这是参数
状态: 沸腾 现在温度: 104
这是参数
状态: 沸腾 现在温度: 105
这是参数
状态: 沸腾 现在温度: 106
这是参数
状态: 沸腾 现在温度: 107
这是参数
状态: 沸腾 现在温度: 108
这是参数
状态: 沸腾 现在温度: 109
这是参数