• 模拟场景:

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

  现在我们是乙方,需要设计一个 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. android app 压力测试工具-monkey tool

    一.什么是Monkey? Monkey测试是Android自动化测试的一种手段,Monkey测试本身非常简单,就是模拟用户的按键输入,触摸屏输入,手势输入等,看设备多长时间会出异常. Monkey是A ...

  2. 51nod 1693 水群

    基准时间限制:0.4 秒 空间限制:524288 KB 分值: 160 难度:6级算法题  收藏  关注 总所周知,水群是一件很浪费时间的事,但是其实在水群这件事中,也可以找到一些有意思的东西. 比如 ...

  3. 用代码判断当前系统是否支持某个版本的feature

    JDK9已经出来有一段时间了,因此很多流行的Java应用纷纷增添了对JDK9乃至JDK10的支持,比如Tomcat. 我们通过这个链接下载最新的Tomcat源文件包,总共7MB: https://to ...

  4. python零基础学习开篇

    我是某工业大学的一名博士,研究方向是基于人脸的模式识别.很遗憾,毕业后没有继续从事图像处理中模式识别相关研究.多种原因进入了一家国企单位,从事交通方面工作.工作2年中一直迷茫,没有在工作岗位中找到自己 ...

  5. 批量格式化json

    单个文件格式化工具: vscode和sublime都有格式化json的插件. 但是笔者遇到的情况是有几百个文件需要格式化,不可能每个文件都打开,进行分别格式化. 于是写了一个python脚本,非常强大 ...

  6. opencv c++编译

    g++ image2png.cpp -o test `pkg-config --cflags --libs opencv`

  7. Vmware 安装CentOS7时连不上网问题的解决

    在VmWare 上安装Centos7时,装好vmware后还是连不上网,通过查找资料原来是因为有线网卡没有激活,默认centos和redhat7都是不启用有线网卡的,要么手动开启,要么安装时直接启用! ...

  8. Java中的Static修饰符

    static(静态.修饰符):static修饰成员变量时:static修饰成员变量时,那么该成员变量的数据就是一个共享的数据. 静态成员变量的访问方式:方式一: 使用对象进行访问. 对象.属性名 方式 ...

  9. MVCPager学习小记

    1.PageIndexParameterName怎么关联? 答:其实就是Action里面的pageindex参数 例子: @Html.Pager(Model, new PagerOptions { P ...

  10. ES6_Promise 对象 阮一锋

    Promise的含义 promise是异步编程的一种解决方法,比传统的回调函数和事件更合理更强大.他由社区最早提出和实现,ES6将其写进语言标准,统一了用法,原生提供了promise对象.所谓prom ...