­

Head First设计模式——观察者模式

  • 2019 年 10 月 22 日
  • 筆記

1、气象监测应用,错误示范

有一个气象站,分别有三个装置:温度感应装置,湿度感应装置,气压感应装置。WeathData对象跟踪气象站数据,WeathData有MeasurmentsChanged()方法,当感应装置数据变化后就会调用MeasurmentsChanged。目前需求是要三个布告板,分别是气象数据状况(CurrentConditionDisply),气象统计(StaisticsDisply),天气预报(ForcastDisply)用来显示各种的数据。按照这个需求我们可以设计出如下方式

public class WeatherData(){      private float Temperature{get;set;}      private float Humidity{get;set;}      private float Pressure{get;set;}        public void MeasurmentsChanged(){          CurrentConditionDisply.Update(Temperature,Humidity,Pressure);          StaisticsDisply.Update(Temperature,Humidity,Pressure);          ForcastDisply.Update(Temperature,Humidity,Pressure);      }  }    public class CurrentConditionDisply{      public void Update(float temperature,float humidity,float Pressure){          //更新公布数据      }  }  public class StaisticsDisply{      public void Update(float temperature,float humidity,float Pressure){          //更新统计数据      }  }  public class ForcastDisply{      public void Update(float temperature,float humidity,float Pressure){          //更新天气预报      }  }  

按照如上设计也能实现目前需求,但是如果新加入一种布告板或者删除一个布告板,那么我们需要去求改MeasurmentsChanged方法。

此例子带来的问题:

1、我们是针对实现编程,而非争对接口。

2、对于每个新的布告板,我们都得修改代码。

3、无法在运行是动态地增加或者删除布告板。

4、未封装改变的部分,违反了对修改关闭,对扩展开放。

2、使用观察者模式解耦

观察者模式:定义了对象之间的一对多依赖,当一个对象改变时,他的所有依赖都会收到通知并自动更新。

订阅报纸就是典型的观察者模式,出版社即为主题(subject),订阅者即是观察者(observer),当有新报纸时,报社就会派人送新报纸到订阅了该报纸的读者手上。这里先给出订阅模式类图,然后我们再对之前的气象站进行观察者模式封装。

3、利用观察者模式改进气象站

按照观察者模式进行设计和改进气象站代码并测试

    /// <summary>      /// 主题      /// </summary>      public interface Subject      {          public void RegisterObserver(Observer o);          public void RemoveObserver(Observer o);          public void NotifyObserver();      }      /// <summary>      /// 具体主题(气象站)      /// </summary>      public class WeatherData : Subject      {          private List<Observer> observers;          private float Temperature { get; set; }          private float Humidity { get; set; }          private float Pressure { get; set; }            public WeatherData()          {              observers = new List<Observer>();          }          public void RegisterObserver(Observer o)          {              observers.Add(o);          }            public void RemoveObserver(Observer o)          {              observers.Remove(o);          }            //通知观察者          public void NotifyObserver()          {              foreach (var o in observers)              {                  o.Update(Temperature, Humidity, Pressure);              }          }            public void MeasurmentsChanged()          {              NotifyObserver();          }            //数据变化          public void SetMeasurments(float temperature, float humidity, float pressure)          {              Temperature = temperature;              Humidity = humidity;              Pressure = pressure;              MeasurmentsChanged();          }      }        /// <summary>      /// 订阅者      /// </summary>      public interface Observer      {          void Update(float temperature, float humidity, float pressure);      }        public class CurrentConditionDisply : Observer      {          private Subject weatherData;          public CurrentConditionDisply(Subject weatherData)          {              this.weatherData = weatherData;              weatherData.RegisterObserver(this);          }          public void Update(float temperature, float humidity, float pressure)          {              Console.WriteLine($"当前情况布告板:{temperature},{humidity},{pressure}");          }      }      public class StaisticsDisply : Observer      {          private Subject weatherData;          public StaisticsDisply(Subject weatherData)          {              this.weatherData = weatherData;              weatherData.RegisterObserver(this);          }          public void Update(float temperature, float humidity, float pressure)          {              Console.WriteLine($"统计数据布告板:{temperature},{humidity},{pressure}");          }      }      public class ForcastDisply : Observer      {          private Subject weatherData;          public ForcastDisply(Subject weatherData)          {              this.weatherData = weatherData;              weatherData.RegisterObserver(this);          }          public void Update(float temperature, float humidity, float pressure)          {              Console.WriteLine($"天气预报布告板:{temperature},{humidity},{pressure}");          }      }

测试结果: