【0】README
0.1)本文部分文字描述转自“head first 设计模式”, 旨在学习 观察者模式 的基础知识;
0.2)for source code of observer pattern, please visit 观察者模式源代码
0.3)类图概览
【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)观察者模式定义了: 对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖都会受到通知并自动更新;
(干货——观察者模式的作用)
4.4)松耦合的威力: 当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。而观察者模式提供了一种对象设计,让 主题和观察者之间松耦合;
松耦合?: 因为主题和观察者两者是松耦合的,所以当改变主题或观察者其中一方,并不会影响到另一方,所以只要他们之间的接口仍被遵守,我们就可以自由地改变他们;
(干货——什么叫松耦合)
4.5)引入设计原则:为了交互对象间的松耦合设计而努力;
【5】给出该app的建立源码(记住:主题subject就是报社,而观察者observer就是订阅者)
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);
}
}
对以上代码的分析(Analysis)(结合报社——订阅者的交互模式):
A1)WeatherData 实现了主题接口,它就相当于 报社;
A2)当报社有心报纸被出版时(调用setMeasurement()方法),他就会通知(调用 nofityObservers方法)订阅者有新报纸出版,并送货上门;
A3)当订阅者收到新报纸时,他就会更新当前报纸为新报纸,或利用新报纸干一些其他的事情(observer调用 update()方法);
【6】java内置的的观察者模式
6.1)java包内包含最基本的Observer接口和 Observable类,你甚至可以使用 推(push)或拉(pull)的方式传送数据;
6.2)java内置观察者模式的类图结构
对上述类图的分析(Analysis):
WeatherData是我们之前所称谓的主题,从今以后,他被改称为“可观察者(Observable)”;这里,我们不需要在此提供 register(), remove() 和 notifyObservers()方法,因为父类有这些方法了;
6.3)使用java内置的观察者模式实现气象站(将 WeatherData 改成使用 java.util.Observable)
对上图代码的分析(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)观察者模式定义: 在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖他的对象都会受到通知,并自动更新;