• 模拟场景:

  甲方提供了一个气象站的接口,气象站上面装有:温度感应装置、湿度感应装置、气压感应装置。

  现在我们是乙方,需要设计一个 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);
}
}
  • 第一套方案有什么问题?

  显然,这是一个扩展性很差的解决方案,它有如下问题:

  1. 没有针对接口编程。(Display 应该事先一个公共的接口)
  2. 如果需要增加或者删除 Display,都要修改代码。
  3. 不能动态地增加或者删除 Display。
  • 观察者模式:

  定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

  观察者模式 = 主题+观察者(Subject + Observer)。

  • 理想的 WeatherData 设计方案:
  1. Display 对象,作为观察者,需要实现统一的 Observer 接口。
  2. Observer 接口,具有更新 temperature, humidity, pressure 的能力。
  3. WeatherData 对象,作为主题,需要实现 Subject 接口。
  4. Subject 接口,维护一个 Oberver 列表,对外提供将 Observer 加入/移除 列表的接口,并且具有通知所有 Observer 数据变化的能力。
  5. 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的更多相关文章

  1. 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)

    设计模式 ( 十六 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...

  2. 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

      设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...

  3. WUST 设计模式 实验九 观察者模式的应用

    实验九 观察者模式的应用 一.实验目的 掌握外观模式(Observer)的特点: 分析具体问题,使用外观模式进行设计. 二.实验内容和要求   网上商店中如果商品(product)在名称(name). ...

  4. 设计模式之十:观察者模式(Observer)

    观察者模式: 在对象之间定义了一种一对多的依赖关系.当一个对象改变它的状态时,全部依赖它的对象会自己主动接收通知并更新自己的状态. Define a one-to-many dependency be ...

  5. 设计模式九: 观察者模式(Observer Pattern)

    简介 观察者属于行为型模式的一种, 又叫发布-订阅模式. 如果一个对象的状态发生改变,依赖他的对象都将发生变化, 那么这种情况就适合使用观察者模式. 它包含两个术语,主题(Subject),观察者(O ...

  6. 设计模式系列之观察者模式(Observer Pattern)

    意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作 ...

  7. 我理解设计模式C++实现观察者模式Observer Pattern

    概述: 近期中国股市起起伏伏,当然了起伏就用商机,小明发现商机后果断想入市,买入了中国证券,他想在电脑client上,网页上,手机上,iPad上都能够查看到该证券的实时行情,这样的情况下我们应该怎么设 ...

  8. [设计模式-行为型]观察者模式(Observer)

    一句话 事件监听就是观察者模式最好的例子. 概括

  9. 《JAVA设计模式》之观察者模式(Observer)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述观察者(Observer)模式的: 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.模型-视图(Mo ...

  10. Java设计模式十九——责任链模式

    责任链模式 老李的苦恼 每个人在出生的时候,都早已在暗中被标好了三六九等. 老李是一名建筑工地的木匠,和大多数生活在社会最底层的农民工一样,一辈子老实本分,胆小怕事.在他们的心中,谁当老爷都没有区别, ...

随机推荐

  1. 【Python图像特征的音乐序列生成】解析ABC格式的文件(修改版)

    ABC格式,是一个音乐标准,ABC Plus Project最新的标准是2.x. ABC格式的音乐长成这样: X: T:Abacus % Nottingham Music Database S:By ...

  2. ABAP function group和Tomcat library重复加载问题

    ABAP ABAP help文档里对**LOAD-OF-PROGRAM"的关键字是这样描述的: This event keyword defines the program construc ...

  3. codeforce Gym 100500A Poetry Challenge(博弈,暴搜)

    题解:状态压缩之后,暴力dfs,如果有一个选择,能让对手必败,那么就是必胜态,能转移到的状态都是对手的必胜态,或者无法转移,就是必败态. 总算是过了,TLE是因为状态没判重. #include< ...

  4. 团队作业-Beta冲刺(周三)

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1 这个作业要求在哪里 https://edu.cnblo ...

  5. Tarjan 详解

    Tarjan 算法 一.算法简介 Tarjan 算法一种由Robert Tarjan提出的求解有向图强连通分量的算法,它能做到线性时间的复杂度. 我们定义: 如果两个顶点可以相互通达,则称两个顶点强连 ...

  6. Python面向对象(三)

    类的使用:实例化.属性引用 实例化 g1 = Garen('草丛伦1') # 实例化 g2 = Garen('草丛伦2') g3 = Garen('草丛伦3') 类的属性:变量和函数 print(Ga ...

  7. 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 += ...

  8. sql*plus常用指令介紹

    sql*plus常用指令介紹 1.用set指令來設定SQL*Plus的環境參數值 格式: Set 環境參數名 環境參數值 ex:set feedback on set feedback 8.用show ...

  9. 强制类型转换(int)、(int&)和(int*)的区别

    我们先来看两行代码: float x=1.75,y=1.75; cout<<(int)x<<" "<<(int&)y<<en ...

  10. 转 WebService两种发布协议--SOAP和REST的区别

    转发文章 https://blog.csdn.net/zl834205311/article/details/62231545?ABstrategy=codes_snippets_optimize_v ...