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}");          }      }

測試結果: