观察者模式

【0】README
0.1)本文部分文字描述转自“head first 设计模式”, 旨在学习 观察者模式 的基础知识;
0.2)for source code of observer pattern, please visit 观察者模式源代码
0.3)类图概览
观察者模式_第1张图片
【1】实际荔枝
1.1)需求:气象站希望某公司建立一个手机app,有三种布告板,分别显示当前状况,气象统计和简单的预报;
1.2)我公司的工作:建立一个app,利用 WeatherData 对象取得数据,并更新三个布告板: 当前状况、气象统计和天气预报;

【2】对WeatherData 进行分析(Analysis) 
A1)WeatherData 类具有getter 方法,可以取得三个测量值: 温度,湿度和气压;
A2)当新的测量数据准备好时,measurementsChanges()方法就会被调用;
A3)我们需要三个布告板:当前状况布告,气象统计布告,天气预报布告;
A4)此系统必须可以扩展,让其他开发人员建立定制的布告板,用户可以随心所欲地添加或删除任何布告板。初始的布告板有三类:当前状况布告,气象统计布告,天气预报布告;

【3】看一下错误实现(Error)
public class WeatherData {
	Display currentDisplay;
	Display statisticsDisplay;
	Display forecastDisplay;
	
	public void measurementsChanged() {
		double temp = getTemperature();
		double humidity = getHumidity();
		double pressure = getPressure();
		
		/**
		 * 以下3行代码的具体实现就是一个loser的实现:
		 * 针对具体实现编程,会导致以后在增加或删除布告板时必须修改程序
		 */
		currentDisplay.update(temp, humidity, pressure);
		statisticsDisplay.update(temp, humidity, pressure);
		forecastDisplay.update(temp, humidity, pressure);
	}
	public double getTemperature(){
		return 1.0;
	}
	
	public double getHumidity(){
		return 1.0;
	}
	public double getPressure(){
		return 1.0;
	}
}
【4】认识观察者模式
4.1)看看报纸的订阅是怎么回事?(translations)
t1)报社的业务就是出版报纸;
t2)向某家报社订阅了报纸,只要他们有新报纸,就会给你送来;
t3)当你不想再看报纸的时候,会取消订阅,报社就不会送报纸了;
t4)只要报社处于运营状态,就会一直有人订阅报纸或取消订阅;
4.2)出版者+订阅者==观察者模式: 出版者称为主题(subject),而订阅者称为观察者(observer); (干货——观察者模式的具体化)
4.3)观察者模式定义了: 对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖都会受到通知并自动更新; (干货——观察者模式的作用)
观察者模式_第2张图片
观察者模式_第3张图片
4.4)松耦合的威力: 当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。而观察者模式提供了一种对象设计,让 主题和观察者之间松耦合;
松耦合?: 因为主题和观察者两者是松耦合的,所以当改变主题或观察者其中一方,并不会影响到另一方,所以只要他们之间的接口仍被遵守,我们就可以自由地改变他们; (干货——什么叫松耦合)
4.5)引入设计原则:为了交互对象间的松耦合设计而努力;

【5】给出该app的建立源码(记住:主题subject就是报社,而观察者observer就是订阅者)
观察者模式_第4张图片
5.1)实现气象站,建立接口
public interface Subject {
	public void registerObserver(Observer o);
	public void removeObserver(Observer o);
	public void notifyObservers();
}
public interface Observer {
	public void update(float temp, float humidity, float pressure);
}
public interface DisplayElement {
	public void display();
}
5.2)在WeatherData中实现主题接口
import java.util.ArrayList;

public class WeatherData implements Subject{
	private ArrayList observers;
	private float temperature;
	private float humidity;
	private float pressure;
	
	public WeatherData() {
		observers = new ArrayList();
	}
	
	// 设置测量值,并通知观察者.
	public void setMeasurements(float temp, float humidity, 
			float pressure)	{
		this.temperature = temp;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}

	// 当从气象站得到更新观测值时,我们通知观察者.
	public void measurementsChanged(){
		notifyObservers();
	}
	
	@Override
	public void notifyObservers() {
		for (int i = 0; i < observers.size(); i++) {
			Observer observer = (Observer)observers.get(i);
			observer.update(temperature, humidity, pressure);
		}
	}
	
	@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);
		}
	}
}
5.3)建立布告板
public class CurrentDisplay implements Observer, DisplayElement {
	private float temperature;
	private float humidity;
	private float pressure;
	private Subject weatherData;

	public CurrentDisplay(Subject weatherData) {
		this.weatherData = weatherData;
		weatherData.registerObserver(this);
	}

	// 当update() 被调用时,我们把温度和湿度保存起来,然后调用display。
	@Override
	public void update(float temp, float humidity, float pressure) {
		this.temperature = temp;
		this.humidity = humidity;
		this.pressure = pressure;
		display();
	}

	@Override
	public void display() {
		System.out.println("current contions: temperature is " + temperature
				+ ", humidity is " + humidity + ", pressure is " + pressure);
	}

}
5.4)测试程序
public class WeatherStation {
	public static void main(String[] args) {
		WeatherData data = new WeatherData();
		CurrentDisplay display = new CurrentDisplay(data);
		
		data.setMeasurements(1, 23, 30.4f);
	}
}
观察者模式_第5张图片
对以上代码的分析(Analysis)(结合报社——订阅者的交互模式):
A1)WeatherData 实现了主题接口,它就相当于 报社;
A2)当报社有心报纸被出版时(调用setMeasurement()方法),他就会通知(调用 nofityObservers方法)订阅者有新报纸出版,并送货上门;
A3)当订阅者收到新报纸时,他就会更新当前报纸为新报纸,或利用新报纸干一些其他的事情(observer调用 update()方法);

【6】java内置的的观察者模式
6.1)java包内包含最基本的Observer接口和 Observable类,你甚至可以使用 推(push)或拉(pull)的方式传送数据;
6.2)java内置观察者模式的类图结构
观察者模式_第6张图片
对上述类图的分析(Analysis): WeatherData是我们之前所称谓的主题,从今以后,他被改称为“可观察者(Observable)”;这里,我们不需要在此提供 register(), remove() 和 notifyObservers()方法,因为父类有这些方法了;

6.3)使用java内置的观察者模式实现气象站(将 WeatherData 改成使用 java.util.Observable)
观察者模式_第7张图片
对上图代码的分析(Analysis):
A1)setChanged() 方法的代码: 吧 changed标志设置为 true,可能你也会需要 clearChanged() 方法 和 hasChanged() 方法;
A2)nofityObservers()源码:
notifyObservers(Object arg){
    if(changed){
        for every observer on the list{
            call update(this,arg)
        }
        changed = false
    }
}
6.4)观察者模式定义: 在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖他的对象都会受到通知,并自动更新;

你可能感兴趣的:(观察者模式)