《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)

 第二篇 观察者模式

    好久没写文章了,为我的懒惰害臊一下.

    首先还是需求,我们现在有个新项目,做一个气象站的项目,负责提供气象资料(temperature, humidity, pressure)  给天气显示板,这里有2个显示板,一个是状态显示板,一个统计显示板.

《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)_第1张图片

ok,这个很简单,我们立马开始动手做uml图

 

《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)_第2张图片

每当气象站获得新信息的时候,就开始调用UpdateDisplay方法,更新气象显示板的资料,如下代码

public class WeatherData { public IDisplay display1, display2; double _temperature; public Double Temperature { get { return _temperature; } set { _temperature = value; MessurementChanged();} } double _humidity; public Double Humidty { get { return _humidity; } set { _humidity = value; MessurementChanged();} } double _pressure; public Double Pressure { get { return _pressure; } set { _pressure = value;} } public void MessurementChanged() { UpdateDisplay(); } public void UpdateDisplay() { display1.Temperature = this.Temperature; display1.Humidty = this.Humidty; display2.Temperature = this.Temperature; display2.Humidty = this.Humidty; } }

ok,这么做工作的很好,但是,现在又新的显示板加入,怎么办呢,只好更改WeatherData类,加入新的支持,那么如果显示板更改需求,不再需要temperature温度 ,而需要pressure大气压的数值呢,还是要更改WeatherData类,这样,根本无法做到封装的目的,只能面对无穷无尽的修改和重编译.

     这里我们就需要用到观察者模式了,什么是观察者模式,有句话是这么形容的: publish+subscriber=Observer Pattern,或则成为 subject(主题) +observer(观察者), 观察者模式是很重要的一个模式,我们想象下显示生活报纸订阅系统是怎么做的,用户随时订阅报纸,也可以随时退订.只要用户订阅了,那么一有新报纸,就会通知用户,并发送新资料给用户.还有在c#里我们经常用到的delegate,event之类,一开始我常感到很惊奇,这些是怎么做到的呢,其实这些就是观察者模式的一个演化.发布者状态一发生变化,订阅者就接受到消息. 发布者并不知道订阅者的具体情况,他们互相十分独立,这也是面向对象的一个重要原则:尽量使关联事物之间以松耦合链接.观察者模式图示如下.  《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)_第3张图片

当观察者注册的时候,主题把观察者放到一个容器里面.

当观察者退出的时候,主题把观察者从容器里面移除.

当主题状态一发生变化,主题首先从容器里面获得观察者的集合,然后把消息通知这些观察者.

观察者收到消息,就可以做自己想做的.

    我们了解了观察者模式, 那么我们回到气象站项目 , 这里气象站中心就是主题,气象显示板就是观察者.我们可以画uml图如下

《Head First Design Patterns》笔记二:观察者模式(Observer Pattern)_第4张图片

 具体代码如下,分8个类

 第一部分,主题3个类(为了方便观看,把3个文件放在一起)

//file:IObservable.cs using System; public interface IObservable { void RegisterObserver(IObserver observer); void UnRegisterObserver(IObserver observer); void NotifyObserver(); } //file:Subject.cs using System; using System.Collections.Generic; public class Subject:IObservable { private List observerList=new List(); public void RegisterObserver(IObserver observer) { if (!observerList.Contains(observer)) observerList.Add(observer); } public void UnRegisterObserver(IObserver observer) { if (observerList.Contains(observer)) observerList.Remove(observer); } public void NotifyObserver() { foreach(IObserver observer in observerList) { observer.Update(this); } } } //file WeatherData.cs using System; public class WeatherData:Subject { private double _temperature; public double Temperature { get{return _temperature;} set{_temperature=value;MeasurementChanged();} } private double _humidity; public double Humidity { get{return _humidity;} set{_humidity=value;MeasurementChanged();} } private double _pressure; public double Pressure { get{return _pressure;} set{_pressure=value;MeasurementChanged();} } public WeatherData(double temperature,double humidity,double pressure) { this._temperature=temperature; this._humidity=humidity; this._pressure=pressure; } public void MeasurementChanged() { NotifyObserver(); } }

第二部分,观察者部分分4个类,如下

//file:IObserver.cs using System; public interface IObserver { void Update(object sender); } //file:IDisplay.cs using System; public interface IDisplay { void Display(); } //file:GeneralDisplay.cs using System; public class GeneralDisplay:IObserver,IDisplay { private double temperature,humidity; public void Update(object sender) { if (sender is WeatherData) { WeatherData wd=(WeatherData)sender; this.temperature=wd.Temperature; this.humidity=wd.Humidity; Display(); } } public void Display() { Console.WriteLine("current temperature is {0} C,humidity is{1}",temperature,humidity); } } //file:StatisticsDisplay.cs using System; using System.Collections.Generic; public class StatisticsDisplay:IObserver,IDisplay { private List temperatureList=new List(); public void Update(object sender) { if (sender is WeatherData) { WeatherData wd=(WeatherData)sender; temperatureList.Add(wd.Temperature); temperatureList.Sort(); Display(); } } public void Display() { if (temperatureList.Count>0) Console.WriteLine("min/max/avg temperature is {0},{1},{2}",MinTempe(),MaxTempe(),AvgTempe()); } private double MinTempe() { if (temperatureList.Count>0)return temperatureList[0]; else return 0; } private double MaxTempe() { if (temperatureList.Count>0)return temperatureList[temperatureList.Count-1]; else return 0; } private double AvgTempe() { if (temperatureList.Count>0) { double sum=0; foreach(double d in temperatureList) { sum+=d; } return sum/temperatureList.Count; } else return 0; } }

最后就是程序入口,让我们看一下具体效果了,如下

using System; public class Program { public static void Main() { WeatherData wd=new WeatherData(20,80,40); IObserver genDis=new GeneralDisplay(); IObserver staDis=new StatisticsDisplay(); wd.RegisterObserver(genDis); wd.RegisterObserver(staDis); wd.Temperature=25; wd.Temperature=30; wd.Humidity=70; Console.ReadLine(); } }

运行结果如下:

current temperature is 25 C,humidity is80
min/max/avg temperature is 25,25,25
current temperature is 30 C,humidity is80
min/max/avg temperature is 25,30,27.5
current temperature is 30 C,humidity is70
min/max/avg temperature is 25,30,28.3333333333333

 

总结

     当事物之间存在一对多的关系,当“一”变化的时候,其他事物将自动收到消息并更新,这种模式称为观察者模式。

 

思考

      是否感觉有点触发事件的感觉,不错,在c#里面使用delegate和event可以使以上代码更简练.我们通过使用delegate的方式修改代码,分为5个类,Idisplay,GenerealDisplay,StatisticsDisplay,WeatherData,Program.代码如下:

//file 1 IDisplay.cs using System; public interface IDisplay { void OnUpdate(object sender,EventArgs args); void Display(); } //file 2 GeneralDisplay.cs using System; public class GeneralDisplay:IDisplay { private double temperature,humidity; public void OnUpdate(object sender,EventArgs args) { if (sender is WeatherData) { WeatherData wd=(WeatherData)sender; temperature=wd.Temperature; humidity=wd.Humidity; Display(); } } public void Display() { Console.WriteLine("current temperature is {0} C,humidity is {1}",temperature,humidity); } } //file 3 StatisticsDisplay.cs using System; using System.Collections.Generic; public class StatisticsDisplay:IDisplay { private List temperatureLists=new List(); public void OnUpdate(object sender,EventArgs args) { if (sender is WeatherData) { WeatherData wd=(WeatherData)sender; temperatureLists.Add(wd.Temperature); temperatureLists.Sort(); Display(); } } public void Display() { Console.WriteLine("min/max/avg temperature is {0},{1},{2}",GetMinTemp(),GetMaxTemp(),GetAvgTemp()); } public double GetAvgTemp() { int count=temperatureLists.Count; double sum=0; if (count>0) { for(int i=0;i0) return temperatureLists[0]; else return 0; } public double GetMaxTemp() { if (temperatureLists.Count>0) return temperatureLists[temperatureLists.Count-1]; else return 0; } } //file 4 WeatherData.cs using System; public class WeatherData { public delegate void UpdateMethod(object sender,EventArgs args); public event UpdateMethod Update; private double _temperature; public double Temperature{get{return _temperature;}set{_temperature=value;MeasurementChanged();}} private double _humidity; public double Humidity{get{return _humidity;} set {_humidity=value;MeasurementChanged();}} private double _pressure; public double Pressure{get {return _pressure;}set{_pressure=value;MeasurementChanged();}} public WeatherData(double temperature,double humidity,double pressure) { this._temperature=temperature; this._humidity=humidity; this._pressure=pressure; } public void MeasurementChanged() { if (Update!=null) Update(this,new EventArgs()); } } //file 5 Program.cs using System; public class program { public static void Main() { WeatherData wd=new WeatherData(20,80,40); IDisplay dis1=new GeneralDisplay(); IDisplay dis2=new StatisticsDisplay(); wd.Update+=dis1.OnUpdate; wd.Update+=dis2.OnUpdate; wd.Temperature=25; wd.Temperature=30; wd.Humidity=70; } }

这里关键的地方时WeathData类添加的event,delegata,event后台工作我的理解其实就是一种Observer模式.程序运行结果同以前的代码一致,对照着看,可以更好的理解delegate,event和observer模式.

 

下一篇:《Head First Design Patterns》笔记三:装饰者模式(Decorator Pattern)

上一篇:《Head First Design Patterns》笔记一:策略模式(Strategy Pattern)

 

 

 

 

你可能感兴趣的:(Design,Patterns)