• 模拟场景:

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

  现在我们是乙方,需要设计一个 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. javaSe-反射3

    package com.java.chap07.sec04; public class Student { private String name; private Integer age; publ ...

  2. javaScript的注释、变量和基本数据类型

    上一级写了javaScript是用来操作文档对象元素的,这一次带大家看看javaScriput的注释.变量和基本数据类型. 1.注释:注释是什么呢?注释其实就是阻止浏览器解析某一行或者多行代码或描述的 ...

  3. POJ 1845 Sumdiv (数学,乘法逆元)

    题意: 给出数字A和B,要求AB的所有因子(包括AB和1)之和 mod 9901 的结果. 思路: 即使知道公式也得推算一阵子. 很容易知道,先把分解得到,那么得到,那么的所有因子之和的表达式如下: ...

  4. [转]maven项目部署到tomcat

    其实maven项目部署到tomcat的方式很多,我从一开始的打war包到tomcat/webapps目录,到使用tomcat-maven插件,到直接使用servers部署,一路来走过很多弯路. 下面就 ...

  5. NBear简介与使用图解

    NBear简介与使用图解 框架类型:ORM映射框架 简介:NBear是一个基于.Net 2.0.C#2.0开放全部源代码的的软件开发框架类库.NBear的设计目标是尽最大努力减少开发人员的工作量,最大 ...

  6. Centos7离线部署kubernetes 1.13集群记录

    一.说明 本篇主要参考kubernetes中文社区的一篇部署文章(CentOS 使用二进制部署 Kubernetes 1.13集群),并做了更详细的记录以备用. 二.部署环境 1.kubernetes ...

  7. 【android】安卓的权限提示及版本相关

    Only dangerous permissions require user agreement. The way Android asks the user to grant dangerous ...

  8. 【linux】【rpm】确定程序是否 rpm 安装

    执行 rpm -qf 文件名如果结果显示出安装包那就说明是rpm (或者yum)安装 详情参看 rpm -v  (或者 man rpm) ​

  9. 科学计算库Numpy——概述

    Numpy主要用于数组的各种计算. 导入Numpy import numpy as np 数组类型 Numpy的数组类型为numpy.ndarray. array=np.array([1,2,3,4, ...

  10. python爬虫基础10-selenium大全4/8-Webelement

    Selenium笔记(4)Webelement 本文集链接:https://www.jianshu.com/nb/25338984 这是通过find方法找到的页面元素,此对象提供了多种方法,让我们可以 ...