博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
观察者模式学习笔记
阅读量:4677 次
发布时间:2019-06-09

本文共 4957 字,大约阅读时间需要 16 分钟。

## 什么时候需要用观察者模式?

有的时候我们有这样的需求,当某一对象的状态更新了,需要告知其他的对象。同时,其他对象可以退出通知列表,也可以选择重新加入通知列表。这时候,我们就需要用到一种设计模式——观察者模式。

## 场景举例

上面的话太难以理解了,模拟一个应用场景来进行说明。

有一个气象站,能通过一些硬件设备获取到一些气象数据(温度、湿度、大气压)。同时有几个显示屏幕——实时信息、数据统计、气象预报等屏幕。当气象数据更新了之后,这些屏幕也要随着更新数据。另外,该应用还要扩展友好,能提供API接口,能添加或者删除屏幕设备。

场景分析

先分析一下场景,能发现几个对象(object)。气象数据(WeatherData),实时信息屏幕(CurrentConditionDisplay),数据统计屏幕(statisticsDisplay),气象预报屏幕(ForcastDisplay)。

/** * 气象数据 */class WeatherData {    getTemperature();    getHumidity();    getPressure();    measurementsChanged();}
/** * 实时信息屏幕 */class CurrentConditionDisplay() {    display();}
/** * 数据统计屏幕 */class statisticsDisplay() {    display();}
/** * 气象预报屏幕 */class ForcastDisplay() {    display();}

先完善一下 WeatherData的代码

public class WeatherData {    public void measurementsChanged() {        float temp = getTemperature();        float humidity = getHumidity();        float pressure = getPressure();        currentConditionsDisplay.update(temp, humidity, pressure);        statisticsDisplay.update(temp, humidity, pressure);        forecastDisplay.update(temp, humidity, pressure);    }    }

发现不足

上面WeatherData的这段代码好像完成了数据更新的功能。但是有几个不足的地方。

  • 针对实现编程,而不是针对接口编程
  • 当有新的显示屏幕,我们需要改动WeatherData中的measurementsChanged()方法
  • 不能在程序运行是时添加或移除显示屏对象
  • 所有的显示屏对象虽然都有同一个update()方法,却没有实现一个通用接口

如何改进?

  1. 使用接口,这样就能在程序运行时增加或移除显示屏幕
  2. 所有的显示屏幕实现一个通用显示接口,实现该接口的update()方法。

改进的具体实现,先放着。先回到观察者模式上来。

重新审视观察者模式

举个更接近观察者模式定义的例子:

就像订阅报纸一样,你可以订阅报纸,这样当有新的报纸到了,就有新的报纸看。如果你取消订阅了,那下一期的报纸就无法看到了。

上面这句话有两种行为发布订阅。观察者模式其实就是这样的

Publisher + Observer = Observer Pattern

翻译成中文就是:发布者 + 观察者 = 观察者模式

说了这么多,是时候来一个官方定义了。

The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

翻译一下就是:

观察者模式 定义了对象间一对多的关系。所以当一个对象的状态变化了,它的依赖对象就会被唤醒和自动更新状态。

注意关键点:

  • 一对多
  • 状态变化时,依赖对象随之更新

如何实现这个程序?

解耦

设计原则:Strive for loosely coupled designs between objects that interact.

翻译过来就是:为它们之间有交互的对象解耦而努力

代码关系如下:

/** * Publisher接口 */interface Subject {    registerObserver();    removeObserver();    notifyObserver();}
/** * 气象数据实现Publisher接口,作为一个Subject */public class WeatherData implements Subject {    private float temp;    private float humidity;    private float pressure;    private List
observers; public WeatherData() { observers = new ArrayList
(); } @Override public void registerObserver(IObserver observer) { observers.add(observer); } @Override public void removeObserver(IObserver observer) { int index = observers.indexOf(observer); if (index > 0) { observers.remove(index); } } @Override public void notifyObserver() { for (IObserver ob : observers) { ob.update(getTemp(), getHumidity(), getPressure()); } } public void measurementsChanged() { notifyObserver(); } public void setMeasurements(float temp, float humidity, float pressure) { this.temp = temp; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } public float getTemp() { return temp; } public void setTemp(float temp) { this.temp = temp; } public float getHumidity() { return humidity; } public void setHumidity(float humidity) { this.humidity = humidity; } public float getPressure() { return pressure; } public void setPressure(float pressure) { this.pressure = pressure; }}
/** * Observer接口 */public interface Observer {    public void update(float temp, float humidity, float pressure);}

因为所有的显示屏都有一个update()方法,因此规定一个公共接口

/** * 屏幕显示接口 */public interface IDisplayElement {      public void display();}

接着实现Observer即显示屏幕

/** * 实时信息显示屏 */public class ConditionsDisplay implements Observer, DisplayElement {    private float temp;    private float humidity;    private ISubject weatherData;    public ConditionsDisplay(ISubject weatherData) {        this.weatherData = weatherData;        this.weatherData.registerObserver(this);    }    @Override    public void update(float temp, float humidity, float pressure) {        this.temp = temp;        this.humidity = humidity;        display();    }    @Override    public void display() {        System.out.println("Current conditions: " + temp + "F degrees and "                + humidity + "% humidity");    }}

其他的几个显示屏类也是类似的,就不写了。

接着写一个测试类App来进行验证

public class App {    public static void main(String[] args) {        WeatherData weatherData = new WeatherData();        ConditionsDisplay conditionsDisplay = new ConditionsDisplay(weatherData);                weatherData.setMeasurements(10.3f, 45.12456f, 123.456f);    }    }

打印结果:

output:-----------------------------------------------------------Current conditions: 10.3F degrees and 45.12456% humidity

总结

  1. 观察者模式是 one-to-many 的关系。一个对象变化,其依赖的对象也随之更新
  2. 为了扩展性,应该是面向接口编程而不是面向实现编程
  3. Publisher + Observer = Observer Pattern

转载于:https://www.cnblogs.com/stayfoolishstayhungry/p/4440736.html

你可能感兴趣的文章
vhdl verilog
查看>>
LeetCode 6 ZigZag Conversion 模拟 难度:0
查看>>
bootstrap入门-4.排版及其他固定样式
查看>>
WEB安全之解决CC攻击
查看>>
Html5 01(data-attributes、form-types【只在移动端使用】、svg)
查看>>
python之random模块
查看>>
visor 发布
查看>>
nginx 隐藏版本信息
查看>>
百事世界杯之旅
查看>>
Launch VINS-Mono with Realsense D435i in RTAB-Map
查看>>
以一点为中心旋转动画实现,摇摆动画
查看>>
js去除范围内所有标签并显示指定字符串
查看>>
结对项目进度2
查看>>
git + git flow 的简单介绍
查看>>
Servlet详解(四)--Request与Response
查看>>
如果我们想要交换两个数字,就可以使用位运算
查看>>
求给出第 K个 N位二进制数,该二进制数不得有相邻的“1”
查看>>
P1059 明明的随机数【去重排序】
查看>>
HDU 1060 Leftmost Digit【log10/求N^N的最高位数字是多少】
查看>>
tomcat配置文件web.xml与server.xml解析--重要
查看>>