什么是观察者模式
它定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知。
设计原则
为了交互对象之间的松藕合设计而努力:松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。
图解观察者模式
一个新的对象需要订阅:当有一个新的需要订阅的对象时,需要先向主题对象调用注册接口注册订阅信息。
新的订阅者:有了新的订阅者后,主题对象将向订阅者4也推送订阅消息 。
数据更新:一旦数据有更新,将向所有订阅者更新信息 。
有订阅者需要离开:有订阅者需要离开时,将该订阅者在订阅者列表中移除。
离开后:不再向离开的订阅者推送消息。
例子
现在有一个气象站和布告站(湿度,温度,气压),WeatherData对象(获取气象站数据,更新布告站),我们的工作就是建立一个应用,利用WeatherData对象取得数据,并更新三个布告板:目前状况,气象统计和天气预报。
定义观察者模式:类图
设计气象站
实现气象站
主题接口:
public interface Subject { void registerObserver(Observer o);//注册 void removeObserver(Observer o);//删除 void notifyObservers();//改变状态通知 }
观察者接口:
public interface Observer { /// <summary> /// 当气象观察者改变时,主题把这些状态值当作方法参数,传送给观察者。所有观察者都是实现此方法。 /// </summary> void update(float temp, float humidity, float pressure); }
显示接口(非必需):
public interface DisplayElement { void display();//当布告栏需要显示时,调用此方法 }
主题对象:
public class WeatherData : Subject//实现主题接口 { private List<Observer> observers;//用来记录观察者 private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new List<Observer>(); } public void registerObserver(Observer o)//注册观察者时,添加 { observers.Add(o); } public void removeObserver(Observer o)//注销观察者时,删除 { observers.Remove(o); } public void notifyObservers()//把消息通知所有观察者,因为它们都实现了update { foreach (Observer Observer in observers) { Observer.update(temperature, humidity, pressure); } } public void measurementChanged()//更新数据,通知观察者 { notifyObservers(); } public void setMeasurements(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; this.pressure = pressure; measurementChanged(); } }
观察者对象:
public class CurrentConditionsDisplay : Observer, DisplayElement//实现观察者接口和显示接口 { private float temperature; private float humidity; private Subject weatherDate; public CurrentConditionsDisplay(Subject weatherDate) { this.weatherDate = weatherDate; weatherDate.registerObserver(this);//在构造方法中注册(订阅) } public void display() { Console.WriteLine($"temperature:{temperature},humidity:{humidity}"); } public void update(float temp, float humidity, float pressure)//当此方法被调用时,更新温度和湿度并显示 { this.temperature = temp; this.humidity = humidity; display(); } }
测试:
static void Main(string[] args) { WeatherData weatherData = new WeatherData();//建立一个主题对象 CurrentConditionsDisplay currentConditions = new CurrentConditionsDisplay(weatherData);//注册(订阅) //模拟数据 weatherData.setMeasurements(80, 54, 34); weatherData.setMeasurements(1, 2, 3); weatherData.setMeasurements(12, 23, 34); Console.ReadKey(); }
运行结果: