設(shè)計模式學(xué)習(xí)專欄三--------觀察者模式

設(shè)計模式學(xué)習(xí)專欄三--------觀察者模式

場景


建立一個氣象站應(yīng)用, 利用WeatherData對象取得數(shù)據(jù),并更新三個布告板: 目前狀況 , 氣象統(tǒng)計 , 天氣預(yù)報

image

此系統(tǒng)中的三個部分是氣象站(獲取實際氣象數(shù)據(jù)的物理裝置) , WeatherData對象(追蹤來自氣象站的數(shù)據(jù),并更新布告板) 和 布告板(顯示目前天氣狀況給用戶看.)

WeatherData對象知道如何跟物理氣象站聯(lián)系,以取得更新的數(shù)據(jù).WeatherData對象會隨即更新三個布告板的顯示: 目前狀況(溫度 , 濕度 , 氣壓), 氣象統(tǒng)計和天氣預(yù)報

剛開始實現(xiàn)方式

image
//WeatherData構(gòu)造函數(shù)  , 當(dāng)新公告板加入時, 也要跟著改變
public WeatherData(CurrentConditionsDisplay currentConditionsDisplay,
                       StatisticsDisplay statisticsDisplay,ForecastDisplay forecastDisplay) {
        this.currentConditionsDisplay = currentConditionsDisplay;
        this.statisticsDisplay = statisticsDisplay;
        this.forecastDisplay = forecastDisplay;
    }

如何解決


分析可變部分

  1. 在weatherData的構(gòu)造函數(shù)中 , 對布告板的加入與移除

  2. 在收到氣象數(shù)據(jù)變化時, 需要通知所有已加入的布告板

觀察者模式總覽


定義:在對象之間定義一對多的依賴,這樣一來, 當(dāng)一個對象改變狀態(tài),依賴它的對象都會收到通知,并自動更新

  • 類圖

    image
  • 模式的理解

    • 角色

      • 主題Subject : 主題對象管理某些數(shù)據(jù) , 當(dāng)主題內(nèi)的數(shù)據(jù)改變時 , 就會通知觀察者
      • 觀察者Observer : 觀察者已經(jīng)訂閱主題, 以便在主題數(shù)據(jù)改變時能收到更新 , 當(dāng)不想訂閱主題時,也能隨時移除訂閱
    • 細(xì)節(jié)

      • 使用觀察者模式在任意時候都能 增加/刪除新的觀察者,而不修改原有代碼

      • 觀察者模式 對數(shù)據(jù)推送有兩種方式 推(push)和拉(pull)

        • 推送方式:
          • 當(dāng)主題通知變化時, 主題攜帶著數(shù)據(jù)通知觀察者.
        • 拉取方式
          • 當(dāng)主題通知變化時, 觀察者通過主題的引用 , 去獲取主題中的數(shù)據(jù)信息
    • 觀察者模式提供了一種對象設(shè)計,讓主題和觀察者之間松耦合

      • 對主題而言, 它只知道觀察者實現(xiàn)了某個接口(Observer). 而不需要知道觀察者的具體實現(xiàn)是誰, 做了些什么與其他細(xì)節(jié)
      • 對觀察者而言, 它不需要關(guān)心主題細(xì)節(jié), 只知道可以注冊/移除主題 , 并且主題有數(shù)據(jù)更新時會調(diào)用update方法傳入數(shù)據(jù)

核心代碼部分

  • 主題

    public interface Subject {
      public void registerObserver(Observer o);
      public void removeObserver(Observer o);
      public void notifyObservers();
    }
    
  • 觀察者

    public interface Observer {
      public void update(float temp, float humidity, float pressure);
    }
    
    
  • WeatherData

    public class WeatherData implements Subject {
      private ArrayList<Observer> observers;
      private float temperature;
      private float humidity;
      private float pressure;
      
      public WeatherData() {
          observers = new ArrayList<Observer>();
      }
      
      public void registerObserver(Observer o) {
          observers.add(o);
      }
      
      public void removeObserver(Observer o) {
          int i = observers.indexOf(o);
          if (i >= 0) {
              observers.remove(i);
          }
      }
      
      public void notifyObservers() {
            //遍歷所有的觀察者,調(diào)用update方法
          for (Observer observer : observers) {
              observer.update(temperature, humidity, pressure);
          }
      }
      
      public void measurementsChanged() {
          notifyObservers();
      }
      //氣象站數(shù)據(jù)改變時調(diào)用的方法
      public void setMeasurements(float temperature, float humidity, float pressure) {
          this.temperature = temperature;
          this.humidity = humidity;
          this.pressure = pressure;
          measurementsChanged();
      }
      //其他的get方法
    }
    
  • 觀察者--今日布告板

    public class CurrentConditionsDisplay implements Observer, DisplayElement {
      private float temperature;
      private float humidity;
      private Subject weatherData;    //持有主題引用 , 用于拉取數(shù)據(jù)/刪除主題
      
      public CurrentConditionsDisplay(Subject weatherData) {
          this.weatherData = weatherData;
          weatherData.registerObserver(this);
      }
      
      public void update(float temperature, float humidity, float pressure) {
          this.temperature = temperature;
          this.humidity = humidity;
          display();
      }
      
      public void display() {
          System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
      }
    }
    
  • 主程序 ----主題數(shù)據(jù)改變

    public class WeatherStationHeatIndex {
    
      public static void main(String[] args) {
          WeatherData weatherData = new WeatherData();
          CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
          StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
          ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
    
          weatherData.setMeasurements(80, 65, 30.4f);
          weatherData.setMeasurements(82, 70, 29.2f);
          weatherData.setMeasurements(78, 90, 29.2f);
      }
    }
    
  • 輸出結(jié)果

    Current conditions: 80.0F degrees and 65.0% humidity
    Avg/Max/Min temperature = 80.0/80.0/80.0
    Forecast: Improving weather on the way!
    
    Current conditions: 82.0F degrees and 70.0% humidity
    Avg/Max/Min temperature = 81.0/82.0/80.0
    Forecast: Watch out for cooler, rainy weather
    
    Current conditions: 78.0F degrees and 90.0% humidity
    Avg/Max/Min temperature = 80.0/82.0/78.0
    Forecast: More of the same
    

Java內(nèi)置的觀察者模式

  • 主題 ==> java.util.Observable

  • 觀察者 ==> java.util.Observer

  • 類圖

    image
  • 使用

    • 把對象變成觀察者 , 實現(xiàn)Observer接口, 使用addObserver()或者deleteObserver()進(jìn)行 訂閱/刪除主題

    • 可觀察者(主題)送出通知

      • 調(diào)用setChanged()方法, 標(biāo)記數(shù)據(jù)已改變

        setChanged(){
            changed = true;
        }
        
        notifyObservers(Object arg){
            if(changed){          //只有當(dāng)changed為true時才進(jìn)行通知
                for every observer on the list{
                    call update(this,arg)
                }
                changed = false;  //通知觀察者后,將changed設(shè)置為false
            }
        }
        
        notifyObservers(){
            notifyObservers(null);
        }
        
      • 調(diào)用notifyObservers() 通知所有觀察者

        • notifyObservers();
        • notifyObservers(Object args);
    • 觀察者接收通知

      • update(Observable o , Object arg) //拿到可觀察者引用,即可拉取數(shù)據(jù)
      public void update(Observable obs, Object arg) {
              if (obs instanceof WeatherData) {
                  WeatherData weatherData = (WeatherData)obs;
                  this.temperature = weatherData.getTemperature();
                  this.humidity = weatherData.getHumidity();
                  display();
              }
          }
      

參考

? 書籍: HeadFirst設(shè)計模式

? 代碼參考地址: 我就是那個地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市驶乾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疙咸,老刑警劉巖风科,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異贼穆,居然都是意外死亡故痊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門慨菱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人符喝,你說我怎么就攤上這事∥吠螅” “怎么了茉稠?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長流昏。 經(jīng)常有香客問我吞获,道長,這世上最難降的妖魔是什么各拷? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任烤黍,我火速辦了婚禮,結(jié)果婚禮上速蕊,老公的妹妹穿的比我還像新娘。我一直安慰自己跟啤,他們只是感情好唉锌,可當(dāng)我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布袄简。 她就那樣靜靜地躺著,像睡著了一般绿语。 火紅的嫁衣襯著肌膚如雪候址。 梳的紋絲不亂的頭發(fā)上种柑,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天莹规,我揣著相機(jī)與錄音泌神,去河邊找鬼。 笑死欢际,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的患久。 我是一名探鬼主播浑槽,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼篙挽!你這毒婦竟也來了镊靴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤煮落,失蹤者是張志新(化名)和其女友劉穎踊谋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褪子,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡嫌褪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了裙秋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡进宝,死狀恐怖枷恕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情徐块,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布扳剿,位于F島的核電站昼激,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瞧掺。R本人自食惡果不足惜纷宇,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望上陕。 院中可真熱鬧拓春,春花似錦、人聲如沸硼莽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匆光。三九已至,卻和暖如春夺巩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柳譬。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留销部,地道東北人制跟。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親逢净。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本章目錄如下: 一、階段一 二峭弟、階段二 三脱拼、設(shè)計原則總結(jié) 本章需求是設(shè)計一個氣象展示應(yīng)用,并通過代碼迭代熄浓、優(yōu)化過程...
    黑夜0411閱讀 572評論 0 0
  • 客戶需求 程序設(shè)計 一個氣象站對應(yīng)著多個客戶端,氣象站的數(shù)據(jù)一發(fā)生變化俯在,客戶端的數(shù)據(jù)也要隨著更新娃惯,這就形成了一種依...
    BlainPeng閱讀 995評論 1 17
  • 概念: ??定義了對象之間一對多依賴,這樣一來劈猿,當(dāng)一個對象改變狀態(tài)時,他的所有依賴著都會收到通知并自動更新揪荣。觀察者...
    暴走的小陌閱讀 301評論 0 2
  • 觀察者模式:定義了對象之間的一對多依賴仗颈,這樣一來佛舱,當(dāng)一個對象改變狀態(tài)時挨决,它的所有依賴都會收到通知并自動更新。 類圖...
  • 本文參照《Head First 設(shè)計模式》肆捕,轉(zhuǎn)載請注明出處對于整個系列盖高,我們按照這本書的設(shè)計邏輯,使用情景分析的方...
    詭異的葉子閱讀 822評論 0 4