• 模拟场景:

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

  现在我们是乙方,需要设计一个 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. vue分环境打包配置不同命令

    1.安装cross-env (cross-env能跨平台地设置及使用环境变量)cnpm/npm  i  cross-env -D 2.新建模板 红色的为相关文件 3.配置各个文件 (1)config下 ...

  2. 【LeetCode】4.Median of Two Sorted Arrays 两个有序数组中位数

    题目: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the ...

  3. 小技巧:unicode RLO

    unicode 控制字符 RLO 可以将位于其后的文字翻转. 于是可以被病毒利用. 如图 重命名文件,在gpj前插入unicode RLO,之后若不小心,可能会被欺骗,误以为是jpg文件. 如果修改程 ...

  4. 使用控件的Tag属性传递信息

    实现效果: 知识运用: Control类的Tag属性 //获取或设置包含 有关控件的数据的对象 public object Tag {get;set;} 实现代码: private void Form ...

  5. 报bug

    在打印输出seg的gt数据的时候,出现了gt数据突然很大突然很小的情况,一般这种都是访问了其他内存

  6. java ArrayList remove 2 及正确方法

    https://www.cnblogs.com/chrischennx/p/9610853.html 正确方式 方法一,还是fori,位置前挪了减回去就行了, remove后i--: public v ...

  7. Angular-constructor和ngOnInit区别

    参考文档:https://blog.csdn.net/u010730126/article/details/64486997 总结:constructor做依赖注入,避免业务操作: ngOninit做 ...

  8. virtualvenv+django+uWSGI+nginx 部署

    原创博文 转载请注明出处! 1. virtualvenv 2. django 3. uWSGI 4. nginx 5. 踩坑记录 1. virtualvenv virtualvenv install ...

  9. thinkphp5开发restful-api接口学习 笔记二

    目录 第4节 为api项目搭建数据库 第5节 使用markdown书写接口文档 第6节(判断数据库中是否有此用户) 第7节 为项目配置URL 需求分析 配置主域名和二级域名 使用tp5路由进行URL解 ...

  10. Golang map并发 读写锁

    golang并发 一:只有写操作 var ( count int l = sync.Mutex{} m = make(map[int]int) ) //全局变量并发写 导致计数错误 func vari ...