观察者模式:在对象之间定义一对多的以来,这样一来,当一个对象改变状态,依赖它的对象都会收到通知。
观察者模式在生活当用有很多应用,比如我们在一个报社订阅了一份报纸,每当有新的新闻时,报社会通知每个订阅者。而且订阅者可以随时随地的加入或退出系统。
观察者模式由主题(一)和观察者(多)组成。
比如我们有一个气象监测应用,每当气象有变化时,都会通知各地的显示面板。
首先进入我们的分析(抽象)阶段:谁是一,谁是多,当然气象站(Subject)是一,面板(Observer)是多了。
1. 创建主题, 主题具有注册,撤销, 和通知方法。
public interface Subject {
/**
* 注册观察者
* @param o
*/
void registerObserver(Observer o);
/**
* 删除观察者
* @param o
*/
void removerObserver(Observer o);
/**
* 通知观察者
*/
void notifyObservers();
}
2. 创建观察者,观察者具有update() 方法,当主题改变时用来通知 观察者。
public interface Observer {
/**
* 所有观察者必须实现这个方法
* @param temp
* @param humidity
* @param pressure
*/
void update(float temp, float humidity,float pressure);
}
因为都会有显示行为,所以抽象为公共的接口。
public interface DisplayElement {
void display();
}
3. 创建具体类
具体主题:当数值改变,需要通知观察者
public class WeatherDate implements Subject {
//多个观察者对象
private ArrayList observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherDate() {
this.observers = new ArrayList();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removerObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
@Override
public void notifyObservers() {
for (int i = 0; i < observers.size(); i++) {
Observer observer = (Observer) observers.get(i);
observer.update(temperature,humidity,pressure);
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setMeasurements(float temperature,float humidity,float pressure){
this.temperature =temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
具体观察者:自定义自己的显示方式,可以自己实现多个
public class StatisticsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float[] temperatures;
private int len = 0;
private Subject weatherDate;
public StatisticsDisplay(Subject weatherDate) {
this.weatherDate = weatherDate;
temperatures = new float[3];
weatherDate.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
temperatures[len] = temp;
len++;
display();
}
@Override
public void display() {
if (len > 1){
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (temperatures[j] > temperatures[j + 1]) {
float temp = temperatures[j];
temperatures[j] = temperatures[j + 1];
temperatures[j + 1] = temp;
}
}
}
}
System.out.println("Avg/Max/Min temperature = " + (temperatures[0] + temperatures[len -1]) / 2.0f + "/" +temperatures[len -1]+ "/" + temperatures[0]);
}
}
3. 测试
public class DoMain {
public static void main(String[] args) {
WeatherDate weatherDate = new WeatherDate();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherDate);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherDate);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherDate);
weatherDate.setMeasurements(80,65,30.4f);
weatherDate.setMeasurements(82,70,29.2f);
weatherDate.setMeasurements(78,90,29.2f);
}
}
4. 结果
Current conditions: 80.0 F degrees and 65.0 % humidity
Avg/Max/Min temperature = 80.0/80.0/80.0
Forecast : Improving weather on the way!
Current conditions: 82.0 F degrees and 70.0 % humidity
Avg/Max/Min temperature = 81.0/82.0/80.0
Forecast : Watch out for cooler, rainy weather
Current conditions: 78.0 F degrees and 90.0 % humidity
Avg/Max/Min temperature = 80.0/82.0/78.0
Forecast : More of the same
总结:因为松耦合的设计,可以让主题与观察者之间交互,又不必清楚彼此的细节。改变其中一方,并不会影响另一方,所以只要他们之间的接口仍被遵守,我们就可以自由的改变他们。Java Util 包中实现了Observable,但是因为他是一个类,并不是一个接口,因为JAVA 是单继承,会有一些限制,所以最好还是我们自己来实现。建议大家看《Head First 设计模式》通俗易懂