设计模式(十九)观察者模式 Observer
- 模拟场景:
甲方提供了一个气象站的接口,气象站上面装有:温度感应装置、湿度感应装置、气压感应装置。
现在我们是乙方,需要设计一个 WeatherData 对象,从气象站获取数据,并且利用这些数据,更新三个布告板(当前状况、气象统计、天气预报)。
- 第一版解决方案:
通过简单地分析,我们可以很快确定一套解决方案:
WeatherData 提供一个 measurementsChanged() 方法,当这个方法被调用了,去实时获取气象站的数据,然后更新到三个布告板上。
public class BadWeatherData {
@Getter
private float temperature;
@Getter
private float humidity;
@Getter
private float pressure;
private CurrentConditionsDisplay currentConditionDisplay;
private StatisticsDisplay statisticsDisplay;
private ForecastDisplay forecastDisplay;
public BadWeatherData() {
// some initialized function for displays
}
// We don't care how it be called, we only know is when it is called, we will update displays.
public void measurementsChanged() {
// We don't care how it gets data
float temperature = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionDisplay.update(temperature, humidity, pressure);
statisticsDisplay.update(temperature, humidity, pressure);
forecastDisplay.update(temperature, humidity, pressure);
}
}
- 第一套方案有什么问题?
显然,这是一个扩展性很差的解决方案,它有如下问题:
- 没有针对接口编程。(Display 应该事先一个公共的接口)
- 如果需要增加或者删除 Display,都要修改代码。
- 不能动态地增加或者删除 Display。
- 观察者模式:
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
观察者模式 = 主题+观察者(Subject + Observer)。
- 理想的 WeatherData 设计方案:
- Display 对象,作为观察者,需要实现统一的 Observer 接口。
- Observer 接口,具有更新 temperature, humidity, pressure 的能力。
- WeatherData 对象,作为主题,需要实现 Subject 接口。
- Subject 接口,维护一个 Oberver 列表,对外提供将 Observer 加入/移除 列表的接口,并且具有通知所有 Observer 数据变化的能力。
- Observer 可以主动 订阅/取消 Subject。
- UML 类图(为了防止混乱,类图只显示一个 Display 对象):

- 第二版解决方案:
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
public interface DisplayElement {
void display();
}
@Data
public final class WeatherData implements Subject { private float temperature;
private float humidity;
private float pressure; private List<Observer> observers = new ArrayList<>(); public void measurementsChanged() {
notifyObservers();
} @Override
public void registerObserver(Observer observer) {
observers.add(observer);
} @Override
public void removeObserver(Observer observer) {
observers.remove(observer);
} @Override
public void notifyObservers() {
observers.forEach(observer -> observer.update(temperature, humidity, pressure));
}
}
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
}
public class ForecastDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public ForecastDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("Will show forecast related data");
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
}
public class StatisticsDisplay implements Observer, DisplayElement {
private float temperature;
private Subject weatherData;
public StatisticsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("Statistics will show average temperature");
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
display();
}
}
设计模式(十九)观察者模式 Observer的更多相关文章
- 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)
设计模式 ( 十六 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...
- 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)
设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...
- WUST 设计模式 实验九 观察者模式的应用
实验九 观察者模式的应用 一.实验目的 掌握外观模式(Observer)的特点: 分析具体问题,使用外观模式进行设计. 二.实验内容和要求 网上商店中如果商品(product)在名称(name). ...
- 设计模式之十:观察者模式(Observer)
观察者模式: 在对象之间定义了一种一对多的依赖关系.当一个对象改变它的状态时,全部依赖它的对象会自己主动接收通知并更新自己的状态. Define a one-to-many dependency be ...
- 设计模式九: 观察者模式(Observer Pattern)
简介 观察者属于行为型模式的一种, 又叫发布-订阅模式. 如果一个对象的状态发生改变,依赖他的对象都将发生变化, 那么这种情况就适合使用观察者模式. 它包含两个术语,主题(Subject),观察者(O ...
- 设计模式系列之观察者模式(Observer Pattern)
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作 ...
- 我理解设计模式C++实现观察者模式Observer Pattern
概述: 近期中国股市起起伏伏,当然了起伏就用商机,小明发现商机后果断想入市,买入了中国证券,他想在电脑client上,网页上,手机上,iPad上都能够查看到该证券的实时行情,这样的情况下我们应该怎么设 ...
- [设计模式-行为型]观察者模式(Observer)
一句话 事件监听就是观察者模式最好的例子. 概括
- 《JAVA设计模式》之观察者模式(Observer)
在阎宏博士的<JAVA与模式>一书中开头是这样描述观察者(Observer)模式的: 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.模型-视图(Mo ...
- Java设计模式十九——责任链模式
责任链模式 老李的苦恼 每个人在出生的时候,都早已在暗中被标好了三六九等. 老李是一名建筑工地的木匠,和大多数生活在社会最底层的农民工一样,一辈子老实本分,胆小怕事.在他们的心中,谁当老爷都没有区别, ...
随机推荐
- 【Python图像特征的音乐序列生成】解析ABC格式的文件(修改版)
ABC格式,是一个音乐标准,ABC Plus Project最新的标准是2.x. ABC格式的音乐长成这样: X: T:Abacus % Nottingham Music Database S:By ...
- ABAP function group和Tomcat library重复加载问题
ABAP ABAP help文档里对**LOAD-OF-PROGRAM"的关键字是这样描述的: This event keyword defines the program construc ...
- codeforce Gym 100500A Poetry Challenge(博弈,暴搜)
题解:状态压缩之后,暴力dfs,如果有一个选择,能让对手必败,那么就是必胜态,能转移到的状态都是对手的必胜态,或者无法转移,就是必败态. 总算是过了,TLE是因为状态没判重. #include< ...
- 团队作业-Beta冲刺(周三)
这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1 这个作业要求在哪里 https://edu.cnblo ...
- Tarjan 详解
Tarjan 算法 一.算法简介 Tarjan 算法一种由Robert Tarjan提出的求解有向图强连通分量的算法,它能做到线性时间的复杂度. 我们定义: 如果两个顶点可以相互通达,则称两个顶点强连 ...
- Python面向对象(三)
类的使用:实例化.属性引用 实例化 g1 = Garen('草丛伦1') # 实例化 g2 = Garen('草丛伦2') g3 = Garen('草丛伦3') 类的属性:变量和函数 print(Ga ...
- 11.使用while和for循环分别打印字符串s=’asdfer’中每个元素
1).for循环 s = 'asdfer' for i in s: print(i) 2).while循环 s = 'asdfer' while 1: print(s[index]) index += ...
- sql*plus常用指令介紹
sql*plus常用指令介紹 1.用set指令來設定SQL*Plus的環境參數值 格式: Set 環境參數名 環境參數值 ex:set feedback on set feedback 8.用show ...
- 强制类型转换(int)、(int&)和(int*)的区别
我们先来看两行代码: float x=1.75,y=1.75; cout<<(int)x<<" "<<(int&)y<<en ...
- 转 WebService两种发布协议--SOAP和REST的区别
转发文章 https://blog.csdn.net/zl834205311/article/details/62231545?ABstrategy=codes_snippets_optimize_v ...