观察者模式的介绍
观察者模式:对象之间一对多依赖,当一个对象改变状态的时候,它的所有依赖都会收到通知并且自动更新。
这样说可能有些人不能理解,我们来举个生动形象的例子:
许多人以前会经常订阅杂志,杂志社会定期发杂志给订阅者,当然他也可以取消订阅,那么杂志社就不会继续发杂志给订阅者。
这个例子里面杂志社就是可观察者,而订阅者就相当于观察者,杂志社定期更新会通知他的所有依赖也就是订阅者。
再来个图促进理解:
利用到的新原则
- 为交互对象之间的松耦合设计而努力
观察者模式的例子(气象台布告板例子)
UML类图
有空在画图。
实现代码附带一些解释
- Subject接口
/**
* Subject接口为可观察者(主题)接口
* @
*/
public interface Subject {
/**
* @param o 传入参数为观察者接口实现对象
*/
void registerObserver(Observer o);//注册为观察者
void removeObserver(Observer o);//退出观察者
void notifyObserevers();//当主题数据改变时及时候通知观察者。
}
- Observer接口
public interface Observer {//观察者接口
void update(float temperature, float humidity,float pressure);//更新数据
}
- display接口
public interface Display {//显示数据
void display();
}
- WeatherData(实现可观察接口成为可观察者)
public class WeatherData implements Subject {
private ArrayList observers;
private float temperature;//温度
private float humidity;//湿度
private float pressure;//气压
public WeatherData(){
observers = new ArrayList();//用于观察者注册的集合
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if(i>=0){
observers.remove(i);
}
}
@Override
public void notifyObserevers() {
for (Object observer: observers
) {
Observer observer1 = (Observer) observer;
observer1.update(temperature,humidity,pressure);
}
}
public void measurementsChanged(){//更新通知
notifyObserevers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {//改变观察者数据
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
measurementsChanged();
}
//其他扩展方法
}
- CurrentConditionDisplay (实现观察者接口成为观察者)
public class CurrentConditionDisplay implements Observer,Display {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionDisplay(Subject weatherData){//构造方法实现注册为观察者
this.weatherData=weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {//显示数据
System.out.println("CurrentConditionDisplay:"+temperature+"Humidity"+humidity);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature=temperature;
this.humidity=humidity;
display();
}
}
- CurrentConditionDisplayM(实现观察者接口成为观察者)
public class CurrentConditionDisplayM implements Observer,Display {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public CurrentConditionDisplayM(Subject weatherData){
this.weatherData=weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("CurrentConditionDisplayM:"+temperature*3+"Humidity"+humidity/2+"pressure"+pressure*4);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
display();
}
}
- WeatherStation(气象站类也就是测试类)
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay currentConditionDisplay = new CurrentConditionDisplay(weatherData);
CurrentConditionDisplayM currentConditionDisplayM = new CurrentConditionDisplayM(weatherData);
weatherData.setMeasurements(80,68,29.2f);
weatherData.setMeasurements(90,100,23);
}
}
- 打印结果
观察者模式的总结
可观察者和观察者之间用松耦合的形式结合,可观察者只知道观察者实现了观察者的接口,而不知道观察者具体内容。
有多个观察者时候,不可以依赖特定的通知次序。
swing类库中就有很多使用观察者模式的例子,譬如说:点击按钮添加多种监听器,实现不同的功能。
一些补充
在java.util 类库中有实现好的观察者模式。Observable.java(可观察者类是类不是接口),在这类里面有一个setchanged()方法用来标记可观察者的状态的事实,那他的意义是什么呢?我们不需要标记就可以更新啊,其实他的作用是为了控制可观察者的更新频率,我们可以通过这个方法实现上面的气象站例子 三天,或者半个月更新一次,没有这个方法,我们没有办法控制,气象站就会实时更新。具体我们可以java.util类库中Observable.java的源码。
本文参考:《Head First 设计模式》