继续我们的设计模式学习,有个好的“观察者”可以让你开发效率大大提高
直接进入正题,我们用一个气象站程序来模拟此模式。
有一个气象站程序,能对湿度,温度,气压进行监测并显示在“显示”装置上面
模拟图如下,此系统中有三个部分
气象站:获取实际气象数据的装置
WeatherData对象:用来追踪气象站发出的数据,并实时更新到布告栏中
布告栏:显示目前天气状况给用户看的
换个比方来说说什么是观察者模式~~~~
1:报社的业务就是出版报纸。
2:向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来,只要你是他们的客户,你就会一直收到新报纸。
3:当你不想再看报纸的时候,取消订阅,报社就不会给你送新报纸了。
4:只要报社一直存在,那么就一直会有人来订阅或取消订阅报纸的服务。
懂了吗?出版社+订阅者=观察者模式,只不过用在“观察者”中,出版社成为“主题”(Subject),订阅者成为“观察者”(Observer)
OK,让我用视图更好的说明
鸭子要加入了
目前只要主题那边更新数据,在观察者这边就都能获得数据了。
此时狗对象不想当观察者了,它向“主题”提出了“离开”的意愿
狗对象离开了,当动物(主题)对象更新数据时,狗对象是不会更新的,它已经不是观察者了,但同时它也可以回来重新“注册”成观察者。
自此观察者模式的核心流程就是这样了,代码先不急着写,先思考下。
观察者模式定义:定义了对象之间一对多依赖,这么一来,当一个对象改变状态时,它的所有依赖着都会收到自动更新。
这样的设计使得主题和多个观察者之间的依赖性降低了,Subject只管“交互”Observer,至于具体怎么实现内容或其他细节内容,Subject不需要知道,它只知道指向Observer就可以了。任何时候我们都可以增加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的实现类,即使我们随意增加删除观察者都不会影响主题,我们可以独立地复用主题或观察者,如果我们在其他地方需要使用主题或观察者,可以轻易复用,因为二者并非紧耦合。
设计原则一:所做的一切都是为了对象之间能松耦合。(降低依赖度)
注:松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到最低。
主题接口
package Interface;
/**
* 设计模式:观察者模式 主题和观察者之间有一对多关系
*
* @author Joy
*
*/
// 主题接口
public interface Subject {
// 这两个方法都需要一个观察者作为变量(参数设为观察者),该观察者是用来注册和删除的
public void registerObserver(Observer o);
public void removeObserver(Observer o);
// 当主题状态改变时调用这个方法,作用是通知观察者
public void notifyObserver();
}
观察者接口
package Interface;
//观察者接口
public interface Observer {
//当气象观测数据改变时,主题会把新的状态数据已参数形式传递给观察者
public void update(float temp, float humidity, float pressure);
}
显示接口(显示数据)
package Interface;
public interface DisplayElement {
public void display();
}
气象站类(主题实现类)
package Implements;
import java.util.ArrayList;
import Interface.Observer;
import Interface.Subject;
//气象站实现主题接口
//一个气象站(主题)可以更新多个显示(观察者)面板值
public class WeatherData implements Subject {
// 便于记录观察者
private ArrayList observers;
private float temperature;//温度
private float humidity;//湿度
private float pressure;//气压
public WeatherData() {
observers = new ArrayList();
}
// 当注册观察者时,我们只需要把它加入到ArrayList后面即可
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
// 当观察者想取消注册时,从list中移除即可
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i > 0) {
observers.remove(i);
}
}
@Override
public void notifyObserver() {
for (int i = 0; i < observers.size(); i++) {
//建立观察者对象
Interface.Observer observer = (Interface.Observer) observers.get(i);
//将数据更新至观察者对象内
observer.update(temperature, humidity, pressure);
System.out.println("主题更新了数据,观察者那同步更新");
}
}
// 当从气象站得到更新观测值时,我们通知观察者
public void measurementsChanged() {
notifyObserver();
}
//设置温度,湿度,压力值
public void setMeasurements(float temperature, float humidity,
float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
下面是两个观察者实现类,气温湿度显示装置和天气预报装置
package Implements;
import Interface.DisplayElement;
import Interface.Observer;
import Interface.Subject;
//观察者实现类
//气温,湿度显示装置
public class CurrentConditionDisplay implements Observer,DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
//构造器需要weatherData对象,用于注册
public CurrentConditionDisplay(Subject weatherData){
this.weatherData=weatherData;
//注册
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("温度板");
System.out.println("温度:"+temperature+"\t"+"湿度:"+humidity);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature=temperature;
this.humidity=humidity;
//当update调用时,将温度湿度数据保存起来然后调用display
display();
}
}
天气预报类
package Implements;
import Interface.DisplayElement;
import Interface.Observer;
/**
* 天气预报装置
*
* @author Joy
*
*/
public class ForecastDisplay implements Observer, DisplayElement {
private float currentPressure = 29.92f; // 当前压力值(赋个初始值)
private float lastPressure;// 上一次压力值
private WeatherData weatherData;
public ForecastDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
// 注册成观察者
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
lastPressure = currentPressure;
//pressure传过来的压力值
currentPressure = pressure;
display();
}
@Override
public void display() {
System.out.print("天气预报: ");
if (currentPressure > lastPressure) {
System.out.println("天气晴朗");
} else if (currentPressure == lastPressure) {
System.out.println("这次天气状况与上一次相同");
} else if (currentPressure < lastPressure) {
System.out.println("注意降温,阴云多雨天气");
}
}
}
测试类
package TestMain;
import Implements.CurrentConditionDisplay;
import Implements.ForecastDisplay;
import Implements.WeatherData;
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay ccd = new CurrentConditionDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
//第一次天气情况
weatherData.setMeasurements(80f, 65f, 30.4f);
System.out.println();
//第二次天气情况
weatherData.setMeasurements(82f, 70f, 29.2f);
System.out.println();
//第三次天气情况
weatherData.setMeasurements(78f, 90f, 29.2f);
}
}
运行效果
要点:
1:观察者模式定义了对象之间一对多的关系。
2:主题用一个共同接口来更新观察者。(update方法和Subject接口)
3:观察者和可观察者(主题)之间用松耦合的方式结合,可观察者(主题)不知道观察者的细节,只知道观察者实现了观察者接口。
4:Java内置了观察者模式的实现。
自此完成了观察者模式的实例,Java在JDK当中内置主题和观察者的用法,这里为了更好理解,所以我写的是自定义的形式,
这个模式理解起来并不难,但却是个非常有用的模式,你现在就可以试着用观察者和策略模式改改以前写的旧代码,我的感受就是随着学习深入,就觉得以前写的代码很多都是有错误的。。。。。
感谢你看到这里,观察者模式部分结束,本人文笔随便,若有不足或错误之处望给予指点,90度弯腰~很快我会发布下一个设计模式内容,生命不息,编程不止!
参考书籍:《Head First 设计模式》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。