觀察者模式--Head First設計模式【筆記】


觀察者模式:定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新(是不是感覺很神奇!!!)。

      小A公司接了一個為氣象站開發Internet氣象觀測站的項目。項目開發要求:由氣象站提供一個WeatherData對象負責追蹤目前的天氣狀況(溫度、濕度、氣壓),要求公司開發一個應用,有三種布告板,分別及時更新顯示目前的狀況,而且這個應用能夠易於擴展開發新的布告板。

現在我們開始開發吧

1.第一次嘗試

 class WeatherData
    {
        public void measurementsChanged() 
        {
//取得最新測量值
float temp = getTemperature(); float humidity = getHumidity(); float pressure = getPressure(); //更新到各個布告板 CurrentConditionsDisplay.update(temp, humidity, pressure); statisticsDisplay.update(temp, humidity, pressure); forecastDisplay.update(temp, humidity, pressure); } //這里是其他WeatherData方法 }

解析下:代碼看上去蠻漂亮的,但是想想我們的設計原則
1.找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。
2.針對接口編程,而不是針對實現編程。

2.第二次嘗試:觀察者模式

     觀察者模式主要的兩個對象是主題和觀察者,觀察者依賴於此主題,只要主題狀態一有變化,觀察者就會被通知。根據通知的風格觀察者可能因此新值而更新。

接下來我們來看下觀察者模式的一種常見做法:Subject和Observer接口的類設計的做法。

 public  interface Subject
    {
       void registerObserver(Observer o);//以觀察者作為變量,該觀察者是用來注冊的。
       void removeObserver(Observer o);//以觀察者作為變量,該觀察者是用來刪除的。
        void notifyObservers();//當主題狀態改變時,這個方法會被調用,以通知所有觀察者。
    }
 public interface Observer
    {
        void update(float temp,float humidity,float pressure);//所有觀察者都必須實現updata()方法,以實現觀察者接口。
    }
    class WeatherData:Subject 
    {
//ArrayList 來記錄依賴主題的所有觀察者
private ArrayList observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList(); } #region Subject 成員 //當注冊觀察者時,我們只要把它加到ArrayList的后面即可。 public void registerObserver(Observer o) { observers.Add(o ); } //當刪除觀察者時,我們只要把它從ArrayList中刪除即可。 public void removeObserver(Observer o) { int i = observers.IndexOf(o ); if (i >=0) { observers.Remove(i ); } } //有趣的地方來了!在這里,我們把狀態告訴每一個觀察者。
//因為觀察者都實現了update(),所以我們知道如何通知它們。
public void notifyObservers() { for (int i = observers.Count-1;i >=0 ;i -- ) { Observer observer = (Observer)observers[i]; observer.update(temperature ,humidity ,pressure ); } }
//當從氣象站得到更新觀測值時,我們通知觀察者。
public void measurementsChanged() { notifyObservers(); }
// 條件所限,所以我們用這個方法來手動更新觀測值。
public void setMeasurements(float temperature,float humidity,float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } #endregion }
  public interface DisplayElement
    {
        void display();//當布告板顯示時,調用這個方法。
    }
 
//這里我就寫了一個布告板,有興趣的朋友可以自己多寫幾個布告板,體驗下觀察者模式的精髓。
class CurrentConditionsDisplay:Observer ,DisplayElement { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData)//構造器需要 weatherData對象,作為注冊之用。 { this.weatherData = weatherData; weatherData.registerObserver(this ); } #region DisplayElement 成員 //把最近的溫度和濕度顯示出來 public void display() { Console.WriteLine("Current conditions:"+temperature + "F degrees and"+humidity +"% humidity"); } #endregion #region Observer 成員 //當update()被調用時,我們把溫度和濕度保存起來,然后調用display(). public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } #endregion }

測試下:

static void Main(string[] args)
        {
            WeatherData weatherData = new WeatherData();//首先,建立一個WeatherData對象
//建立一個布告板並把WeatherData對象傳給它,currentDisplay 在構造器中往WeatherData對象注冊自己 CurrentConditionsDisplay currentDisplay
= new CurrentConditionsDisplay(weatherData );
//模擬新的氣象測量 weatherData.setMeasurements(
80,65,30.4f); weatherData.setMeasurements(82,70,29.2f); weatherData.setMeasurements(78,90,29.2f); Console.ReadKey(); }

調試顯示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM