本文为HeadFirst读书笔记
认识观察者模式
报社是怎么运作的?
- 报社出版报纸
- 用户向 某家报社订阅报纸,只要报社有新报纸出版了,就会给用户送过来。只要用户是报社的订户,用户就会一直收到新报纸。
- 当用户不想再看报纸的时候,取消订阅,报社就不再送新报纸给用户。
- 只要报社还在运营,就会一直有用户向他们订阅报纸,也一直有用户取消订阅。
定义观察者模式
出版者+订阅者=观察者
当你试图勾勒观察者模式时,可以利用报纸订阅服务来比拟。我们将出版者称为主题(Subject)
,订阅者称为观察者(Observer)
。
观察者模式
定义了对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新。观察者模式提供了一种对象设计,让主题和观察者之间松耦合,当两个对象松耦合后,它们依然可以交互,但是不太清楚彼此的细节。
设计原则
为了交互对象之间的松耦设计合而努力。
实现一个气象站
接口定义
主题接口
每一个主题可以有多个观察者
定义一个主题
接口,包含 注册观察者,删除观察者,通知观察者 功能。其中注册及删除观察者需要有一个观察者作为入参,以表示该观察者被注册或删除。当主题状态改变的时候,NodifyObserver()
方法会被调用,以通知所有观察者。
public interface ISubject
{
void RegisterObserver(IObserver observer);
void RemoveObserver(IObserver observer);
void NodifyObserver();
}
观察者接口
所有观察者接口都实现此接口。这样,当主题在需要通知观察者的时候,有了一个共同的接口。
当气象观测值发生改变时,Update()
方法中的参数会被传递给观察者。
public interface IObserver
{
void Update(float temp, float humidity, float pressure);
}
显示元素接口
不同的布告板需要显示不同的天气元素,所以我们定义一个显示天气元素的接口
public interface IDisplayElement
{
void Display();
}
实现
气象数据类实现
定义一个气象数据类,实现主题接口。其中,我们定义了一个观察者集合来记录观察者,当注册观察者时,我们添加到此集合中,当删除观察者时,我们从集合中移除该观察者。当气象站得到更新气象数据时,我们通知(NodifyObserver()
)观察者。
public class WeatherData : ISubject
{
private List<IObserver> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData()
{
observers = new List<IObserver>();
}
public void RegisterObserver(IObserver observer)
{
observers.Add(observer);
}
public void RemoveObserver(IObserver observer)
{
observers.Remove(observer);
}
public void NodifyObserver()
{
foreach (var observer in observers)
{
observer.Update(temperature, humidity, pressure);
}
}
public void MeasurementsChanged()
{
NodifyObserver();
}
public void SetMeasurements(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
MeasurementsChanged();
}
}
布告板建立
建立布告板,以展示天气数据,比如布告板A仅需要展示气温,布告板需要展示气温及湿度。
以下代码演示了布告板B的实现代码。
public class TackBoardB : IObserver, IDisplayElement
{
private float temperature;
private float humidity;
private ISubject _weatherData;
public TackBoardB(ISubject weatherData)
{
_weatherData = weatherData;
_weatherData.RegisterObserver(this);
}
public void Display()
{
Console.WriteLine($"布告板B:{temperature}℃ and {humidity}% humidity");
}
public void Update(float temperature, float humidity, float pressure)
{
this.temperature = temperature;
this.humidity = humidity;
Display();
}
}
测试气象站程序
static void Main(string[] args)
{
WeatherData weatherData = new WeatherData();
TackBoardB currentConditionsDisplay = new TackBoardB(weatherData);
weatherData.SetMeasurements(10, 50, 30.2f);
weatherData.SetMeasurements(5, 45, 31.2f);
weatherData.SetMeasurements(-1, 48, 32.2f);
}
输出结果如下
布告板A:10℃
布告板B:10℃ and 50% humidity
布告板A:5℃
布告板B:5℃ and 45% humidity
布告板A:-1℃
布告板B:-1℃ and 48% humidity
附
源码: GitHub