意图/定义(intent)

(简短的描述该模式的作用。)
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖着都会收到通知并自动更新。

问题/动机(motivation)

(动机给出来问题以及如何解决这个问题的具体场景。)
气象站应用:建立一个应用,利用WeatherData对象取得数据,并更新三个布告板:目前状况,气象统计和天机预报。

  1. WeatherData类可以获得三个测量值:温度、湿度与气压。
  2. 当新的测量值数据备妥时,changed() 方法就会被调用。
  3. 我们需要实现三个布告板,一旦WeatherData有新的测量,这些布告板必须马上更新。
  4. 此系统必须可扩展,让其他开发人员建立定制的布告板,用户可以随心所欲的添加或删除任何布告板。

WeatherData类图
image.png

适用性(applicability)

(适用性描述模式可以被应用在什么场合。)

  1. 当一个对象状态的改变需要改变其他对象;或实际对象是事先未知的或动态变化的。
  2. 当应用中的一些对象必须观察其他对象时。

    结构(structure)

    (结构提供了图示,显示出参与此模式的类之间的关系。)
    image.png

    参与者(participants)

    (参与者描述在此设计中所涉及到的类和对象在模式中的责任和角色。)

    协作(collaborations)

    (协作告诉我们参与者如何在此模式中合作。)

    优点

  3. 开闭原则:你无须修改发布者类就能引入新的订阅者。

  4. 你可以在运行时建立对象之间的联系。

    缺点

  5. 订阅者的通知顺序是随机的。

    实现/范例代码(implementation/sample code)

    (实现提供了你在实现该模式时需要使用的技巧,以及你应该小心面对的问题。)
    (范例代码提供代码的片段,可能对你的实现有多帮助。) ```dart /// 观察者模式实现气象观测站代码

/// observer.dart 文件 /// 观察者接口 abstract class Observer { // 当主题状态改变时调用 void update(double temperature, double humidity, double pressure); }

/// subject.dart 文件 /// 主题接口 import ‘./observer.dart’;

abstract class Subject { // 注册观察者 void registerObserver(Observer observer); // 删除观察者 void removeObserver(Observer observer); // 通知观察者 void notifyObserver(); }

/// display_element.dart 文件 /// 布告板接口 abstract class DisplayElement { void display(); }

/// weather_data.dart 文件 /// 气象站观测数据类,实现主题接口 import ‘./subject.dart’; import ‘./observer.dart’;

class WeatherData implements Subject { List _observers; // 观察者 double _temperature; // 温度 double _humidity; // 湿度 double _pressure; // 压强

WeatherData() { _observers = new List(); }

@override void registerObserver(Observer observer) { this._observers.add(observer); }

@override void removeObserver(Observer observer) { this._observers.remove(observer); }

@override void notifyObserver() { _observers.forEach((element) { element.update(_temperature, _humidity, _pressure); }); }

// 测量数据发生变化时调用此函数 void measurementsChanged() { this.notifyObserver(); }

// 设置测量值,测试使用方法 void setMeasurements(double temperature, double humidity, double pressure) { this._temperature = temperature; this._humidity = humidity; this._pressure = pressure;

  1. this.measurementsChanged();

} }

/// current_conditions_display.dart 文件 /// 当前天气布告板 import ‘./observer.dart’; import ‘./display_element.dart’; import ‘./weather_data.dart’;

class CurrentConditionsDisplay implements Observer, DisplayElement { WeatherData _weatherData; double _temperature; double _humidity;

CurrentConditionsDisplay(WeatherData weatherData) { _weatherData = weatherData; _weatherData.registerObserver(this); }

@override void update(double temperature, double humidity, double pressure) { _temperature = temperature; _humidity = humidity;

  1. display();

}

@override void display() { print(‘温度:${_temperature};湿度:${_humidity}’); } }

/// forecast_display.dart 文件 /// 天气预报预告版 import ‘./observer.dart’; import ‘./display_element.dart’; import ‘./weather_data.dart’;

class ForecastDisplay implements Observer, DisplayElement { WeatherData _weatherData; double _pressure;

ForecastDisplay(WeatherData weatherData) { _weatherData = weatherData; _weatherData.registerObserver(this); }

@override void update(double temperature, double humidity, double pressure) { _pressure = pressure;

  1. display();

}

@override void display() { print(‘气压:${_pressure}’); } }

/// statistics_display.dat 文件 /// 统计布告板 import ‘./observer.dart’; import ‘./display_element.dart’; import ‘./weather_data.dart’;

class StatisticsDisplay implements Observer, DisplayElement { WeatherData _weatherData; double _temperature; double _humidity; double _pressure;

StatisticsDisplay(WeatherData weatherData) { _weatherData = weatherData; _weatherData.registerObserver(this); }

@override void update(double temperature, double humidity, double pressure) { _temperature = temperature; _humidity = humidity; _pressure = pressure;

  1. display();

}

@override void display() { print(‘温度:${_temperature};湿度:${_humidity};气压:${_pressure}’); } }

/// test.dart 文件 /// 气象监测应用测试代码 import ‘./weather_data.dart’; import ‘./current_conditions_display.dart’; import ‘./forecast_display.dart’; import ‘./statistics_display.dart’;

void main() { WeatherData weatherData = WeatherData(); CurrentConditionsDisplay currentConditionsDisplay = CurrentConditionsDisplay(weatherData); ForecastDisplay forecastDisplay = ForecastDisplay(weatherData); StatisticsDisplay statisticsDisplay = StatisticsDisplay(weatherData);

weatherData.setMeasurements(80, 65, 30.4); weatherData.setMeasurements(60, 55, 20.6); weatherData.setMeasurements(100, 75, 40.8); }

```

已知应用(known uses)

(已知应用用来描述已经在真实系统中发现的模式例子。)

相关模式(related patterns)

(相关模式描述了此模式和其他模式之间的关系。)

  1. 责任链:按照顺序将请求动态的传递给一系列的潜在接受者,直至其中一名接受者对请求进行处理。
  2. 命令:在发送者和请求者之间建立单项链接。
  3. 中介:清除了发送者和请求者之间的直接连接,强制他们通过一个中介对象进行间接沟通。
  4. 观察者:允许接收者动态的订阅或取消接收请求。

    OO知识

    OO基础

  5. 抽象

  6. 封装
  7. 多态
  8. 继承

OO原则

  1. 封装变化
  2. 多用组合少用继承
  3. 针对接口编程,不针对实现编程
  4. 为交互对象之间的松耦合设计而努力

    要点

  5. 观察者模式定义了对象之间一对多的关系。

  6. 主题(也就是可观察者)用一个共同的接口来更新观察者。
  7. 观察者和可观察者之间用松耦合方式结合(loosecoupling),可观察者不知道观察者的细节,只知道观察者实现了观察者接口。
  8. 使用此模式时,你可以从被观察者处推(push)或拉(pull)数据(然而,推的方式被认为更“正确”)。
  9. 有多个观察者时,不可以依赖特定的通知次序。
  10. 有多种观察者模式的实现。
  11. 此模式被应用在许多地方。