設(shè)計(jì)模式之觀察者模式

客戶需求

/**
 * 需求: 
 * 
 * 氣象站提供最新的天氣預(yù)報(bào)信息,包括: 溫度、濕度、氣壓,這些信息一發(fā)生變化, 客戶端的信息需要同時(shí)更新 請用代碼實(shí)現(xiàn)模擬實(shí)現(xiàn)該功能
 * 
 * 
 */

程序設(shè)計(jì)

一個(gè)氣象站對應(yīng)著多個(gè)客戶端,氣象站的數(shù)據(jù)一發(fā)生變化,客戶端的數(shù)據(jù)也要隨著更新,這就形成了一種依賴關(guān)系,并且是一對多的關(guān)系,很顯然,我們可以用觀察者模式來完成此功能

基本概念

  • 定義

定義了對象之間的一對多依賴,這樣一來,當(dāng)一個(gè)對象改變狀態(tài)時(shí),它的所有依賴者都會收到通知并自動(dòng)更新

  • 角色

    • 抽象被觀察者(或者叫主題)

    它是一個(gè)接口或者抽象類,用來把所有觀察者對象的引用保存到一個(gè)集合中。定義三個(gè)方法:注冊觀察者、解除觀察者、通知觀察者;這三個(gè)方法就是被觀察者與觀察者通信的橋梁

    • 抽象觀察者

    為所有的具體的觀察者定義的一個(gè)接口,定義一個(gè)方法:更新;用于獲取被觀察者發(fā)生變化時(shí)更新自己

    • 具體的被觀察者(或者叫主題)

    在被觀察者內(nèi)部狀態(tài)發(fā)生變化,通知所有注冊過的的觀察者。通常實(shí)現(xiàn)或繼承抽象被觀察者

    • 具體的觀察者

    實(shí)現(xiàn)抽象觀察者接口,使自己與具體的被觀察者的狀態(tài)保持一致

  • UML圖

ObserverPattern.png
  • DemoOne

    • 被觀察者

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

        public interface Observer
        {
            public void update(float temp, float humidity, float pressure);
        }
      
    • 具體被觀察者

        public class WeatherDataSubject implements Subject
        {
            private float               temperature;
            private float               humidity;
            private float               pressure;
            /**
             * 記錄所有的觀察者
             */
            private ArrayList<Observer> observers;
        
            public WeatherDataSubject() {
                observers = new ArrayList<>();
            }
        
            @Override
            public void registerObserver(Observer observer)
            {
                observers.add(observer);
            }
        
            @Override
            public void unregisterObserver(Observer observer)
            {
                int indexOf = observers.indexOf(observer);
                if (indexOf >= 0)
                {
                    observers.remove(indexOf);
                }
            }
        
            @Override
            public void notifyObservers()
            {
                for (int i = 0; i < observers.size(); i++)
                {
                    Observer observer = observers.get(i);
                    observer.update(temperature, humidity, pressure);
                }
            }
        
            public void setMeasurements(float temperature, float humidity, float pressure)
            {
                this.temperature = temperature;
                this.humidity = humidity;
                this.pressure = pressure;
                notifyObservers();
            }
        
        }
      
    • 具體觀察者

        public class CurrentConditionsDidsplay implements Observer
        {
            @Override
            public void update(float temp, float humidity, float pressure)
            {
                System.out.println("temperature=" + temp + "\t humidity=" + humidity + "\t pressure=" + pressure);
            }
        }
      
    • 測試

        public class ObserverPatternTest
        {
            public static void main(String[] args)
            {
                WeatherDataSubject subject = new WeatherDataSubject();
                CurrentConditionsDidsplay condition = new CurrentConditionsDidsplay();
                subject.registerObserver(condition);
                subject.setMeasurements(23.0f, 1.0f, 350.0f);
            }
        }
      

以上這種方式只是簡單的實(shí)現(xiàn)了被觀察者數(shù)據(jù)發(fā)生變化時(shí),主動(dòng)將數(shù)據(jù)送過來,是一種推的模式。它不會管觀察者到底需不需要全部的數(shù)據(jù)。但是,有的觀察者可能只需要一點(diǎn)點(diǎn)數(shù)據(jù),不想收到一堆數(shù)據(jù),那此時(shí)怎么辦呢?那被觀察者是否可以提供一個(gè)get方法讓觀察者自己去獲取數(shù)據(jù),僅通知數(shù)據(jù)有變化了?接下來我們看看Java內(nèi)置的觀察者模式

  • UML圖
Java_ObserverPattern.png
  • DemoTwo
    • 具體的被觀察者

      public class WeatherDataObservable extends Observable
      {
          private float   temperature;
          private float   humidity;
          private float   pressure;
      
          public void setMeasurements(float temperature, float humidity, float pressure)
          {
              this.temperature = temperature;
              this.humidity = humidity;
              this.pressure = pressure;
              //僅僅是用來通知觀察者我的狀態(tài)發(fā)生變化了
              setChanged();
              notifyObservers();
          }
      
          public float getTemperature()
          {
              return temperature;
          }
      
          public float getHumidity()
          {
              return humidity;
          }
      
          public float getPressure()
          {
              return pressure;
          }
      }
      
    • 具體的觀察者

      public class CurrentConditionsDidsplayObserver implements Observer
      {
      
          @Override
          public void update(Observable observable, Object obj)
          {
              if (observable instanceof WeatherDataObservable)
              {
                  WeatherDataObservable data = (WeatherDataObservable) observable;
                  float temperature = data.getTemperature();
                  float humidity = data.getHumidity();
                  float pressure = data.getPressure();
                  System.out.println("temperature=" + temperature + "\t humidity=" + humidity + "\t pressure=" + pressure);
              }
          }
      }
      

java內(nèi)置的觀察者模式是屬于拉數(shù)據(jù)模式,被觀察者狀態(tài)發(fā)生變化了,通過setChanged方法僅通知觀察者狀態(tài)發(fā)生了變化,拉不拉數(shù)據(jù)是觀察者的事了,與被觀察者無關(guān)了。但是這種設(shè)計(jì)方式也會有一定的限制:

(1)Observable是一個(gè)類,所以我們的子類需繼承它,若此時(shí)被觀察者需同時(shí)繼承另一個(gè)超類,就會陷入兩難了,畢竟Java不支持多重繼承,這限制了Observable的復(fù)用能力

(2)Observable中的setChanged方法被protected了,這意味著:除非你繼承Observable類,否則你無法創(chuàng)建Observable實(shí)例并組合到你自己的對象中來。“多用組合,少用繼承”

知識總結(jié)

這兩種模式的使用,取決于系統(tǒng)設(shè)計(jì)時(shí)的需要。如果觀察者比較復(fù)雜,并且觀察者進(jìn)行更新時(shí)必須得到一些具體變化的信息,則“推模式”比較合適。如果觀察者比較簡單,則“拉模式”就比較適合。

參考資料

Head First 設(shè)計(jì)模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,973評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,953評論 2 373

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

  • 觀察者模式 Rxjava中運(yùn)用到了觀察者模式,那什么是觀察者模式呢,現(xiàn)在來學(xué)習(xí)一下。正所謂觀察,就是看,細(xì)察事物的...
    cgzysan閱讀 559評論 0 4
  • 前言定義:觀察者設(shè)計(jì)模式定義了對象間的一種一對多的依賴關(guān)系,以便一個(gè)對象的狀態(tài)發(fā)生變化時(shí),所有依賴于它的對象都得到...
    xsp單細(xì)胞閱讀 460評論 0 1
  • 在下載模塊中經(jīng)常要用到的一個(gè)模式就是觀察者模式了,這是為了提高用戶體驗(yàn)所決定的。 但用戶在下載頁面點(diǎn)擊了下載之后,...
    寶塔山上的貓閱讀 466評論 0 2
  • 七年啊 從今天開始你就十七歲了 歷經(jīng)完十六歲的天空你即將迎來新的自己了 怎么樣 十七歲的你想成為一個(gè)怎樣的女孩擁...
    七年盛夏閱讀 972評論 0 2
  • 安昌古鎮(zhèn)是浙江紹興四大古鎮(zhèn)之一,典型的江南水鄉(xiāng)特色,最有特色的是安昌的小橋。 補(bǔ)充說明:紹興是中國國內(nèi)保存古橋數(shù)量...
    haitaopengpai閱讀 416評論 0 5