設(shè)計(jì)模式學(xué)習(xí)—觀(guān)察者模式

1、什么是觀(guān)察者模式蔚万?

? 觀(guān)察者模式是一種關(guān)注對(duì)象之間責(zé)任分配的行為模式。觀(guān)察者模式定義了對(duì)象之間的一對(duì)多依賴(lài)關(guān)系临庇,這樣當(dāng)一個(gè)對(duì)象更改狀態(tài)時(shí)反璃,它的所有依賴(lài)關(guān)系都會(huì)被通知并自動(dòng)更新。此模式中的關(guān)鍵對(duì)象是subject和observer苔巨。理解觀(guān)察者模式的另一種方法是發(fā)布者-訂閱者關(guān)系的工作方式版扩。

觀(guān)察者模式有四個(gè)參與者:

  • Subject:用于注冊(cè)觀(guān)察員。對(duì)象使用此接口注冊(cè)為觀(guān)察者侄泽,并將自己從觀(guān)察者中移除礁芦。

  • Observer :對(duì)象的更新接口,該接口應(yīng)在主題發(fā)生更改時(shí)通知對(duì)象悼尾。所有觀(guān)察者都需要實(shí)現(xiàn)觀(guān)察者接口飒赃。此接口有一個(gè)方法update()旷太,當(dāng)主題的狀態(tài)發(fā)生更改時(shí),將調(diào)用該方法。

  • ConcreteSubject :存儲(chǔ)對(duì)ConcreteObserver對(duì)象感興趣的狀態(tài)呼股。當(dāng)狀態(tài)發(fā)生變化時(shí),它向觀(guān)察者發(fā)送一個(gè)通知懂从。具體的主題總是實(shí)現(xiàn)主題接口败京。notifyobserver()方法用于在狀態(tài)發(fā)生更改時(shí)更新所有當(dāng)前的觀(guān)察者。

  • ConcreateObserver :維護(hù)對(duì)ConcreteSubject對(duì)象的引用泡仗,并實(shí)現(xiàn)Observer接口埋虹。每個(gè)觀(guān)察者注冊(cè)一個(gè)具體的主題來(lái)接收更新。

    2娩怎、場(chǎng)景分析

    ? 體育大廳是一個(gè)了不起的體育愛(ài)好者的體育網(wǎng)站搔课。它們涵蓋了幾乎所有的體育項(xiàng)目,提供最新的新聞截亦、信息爬泥、比賽日期、特定球員或球隊(duì)的信息”廊浚現(xiàn)在袍啡,他們正計(jì)劃以短信服務(wù)的形式提供現(xiàn)場(chǎng)解說(shuō)或數(shù)十場(chǎng)比賽,但僅限于高級(jí)用戶(hù)谷遂。他們的目標(biāo)是在短時(shí)間間隔后發(fā)送短信實(shí)時(shí)比分葬馋、比賽情況和重要事件。作為用戶(hù),您需要訂閱包畴嘶,當(dāng)有現(xiàn)場(chǎng)比賽時(shí)蛋逾,您將收到一條短信到現(xiàn)場(chǎng)解說(shuō)。該站點(diǎn)還提供了一個(gè)選項(xiàng)窗悯,可以隨時(shí)從包中取消訂閱区匣。作為開(kāi)發(fā)人員,體育游說(shuō)團(tuán)要求您為他們提供這個(gè)新功能蒋院。觀(guān)察者的設(shè)計(jì)模式最適合這種情況亏钩,讓我們看看這個(gè)模式,然后為體育大廳創(chuàng)建功能欺旧。

3姑丑、代碼實(shí)現(xiàn)

public interface Subject {
    public void subscribeObserver(Observer observer);
    public void unSubscribeObserver(Observer observer);
    public void notifyObservers();
    public String subjectDetails();
}

主題界面的三個(gè)關(guān)鍵方法是:

  1. subscribeObserver,用于訂閱觀(guān)察員辞友,或者我們可以說(shuō)注冊(cè)觀(guān)察員栅哀,以便如果主題狀態(tài)發(fā)生變化,應(yīng)該通知所有這些觀(guān)察員称龙。

  2. unSubscribeObserver留拾,用于取消訂閱觀(guān)察者,以便如果主題狀態(tài)發(fā)生更改鲫尊,不應(yīng)通知此未訂閱的觀(guān)察者痴柔。

  3. notifyobserver,當(dāng)主體狀態(tài)發(fā)生更改時(shí)疫向,此方法通知已注冊(cè)的觀(guān)察者咳蔚。

    另外還有一個(gè)方法subjectDetails(),這是一個(gè)簡(jiǎn)單的方法搔驼,可以根據(jù)需要使用屹篓。在這里,它的工作是返回主題的細(xì)節(jié)〕着現(xiàn)在,讓我們看看觀(guān)察者接口

    public interface Observer {
        public void update(String desc);
        public void subscribe();
        public void unSubscribe();
    }
    
    1. update()方法由主體在觀(guān)察者上調(diào)用妄荔,以便在主體狀態(tài)發(fā)生更改時(shí)通知它泼菌。

    2. subscribe()方法用于用主題訂閱自身。

    3. unSubscribe()方法來(lái)取消訂閱主題本身啦租。

      public interface Commentary {
          public void setDesc(String desc);
      }
      

      記者使用上面的界面來(lái)更新評(píng)論對(duì)象上的實(shí)時(shí)評(píng)論哗伯,該接口只包含一個(gè)用于更改具體subject對(duì)象狀態(tài)的方法

      public class CommentaryObject implements Subject,Commentary {
          private final List<Observer> observers;
          private String desc;
          private final String subjectDetails;
          public CommentaryObject(List<Observer>observers,String subjectDetails){
              this.observers = observers;
              this.subjectDetails = subjectDetails;
          }
          @Override
          public void subscribeObserver(Observer observer) {
              observers.add(observer);
          }
          @Override
          public void unSubscribeObserver(Observer observer) {
              int index = observers.indexOf(observer);
              observers.remove(index);
          }
          @Override
          public void notifyObservers() {
              System.out.println();
              for(Observer observer : observers){
                  observer.update(desc);
              }
          }
          @Override
          public void setDesc(String desc) {
              this.desc = desc;
              notifyObservers();
          }
          @Override
          public String subjectDetails() {
              return subjectDetails;
          }
      }
      

      上面的類(lèi)作為一個(gè)具體的主題工作,它實(shí)現(xiàn)了subject接口并提供了它的實(shí)現(xiàn)篷角。它還存儲(chǔ)對(duì)注冊(cè)到它的觀(guān)察者的引用焊刹。

      public class SMSUsers implements Observer {
          private final Subject subject;
          private String desc;
          private String userInfo;
      
          public SMSUsers(Subject subject, String userInfo) {
              if (subject == null) {
                  throw new IllegalArgumentException("No Publisher found.");
              }
              this.subject = subject;
              this.userInfo = userInfo;
          }
      
          @Override
          public void update(String desc) {
              this.desc = desc;
              display();
          }
      
          private void display() {
              System.out.println("[" + userInfo + "]: " + desc);
          }
      
          @Override
          public void subscribe() {
              System.out.println("Subscribing " + userInfo + " to " + subject.subjectDetails() + " ...");
              this.subject.subscribeObserver(this);
              System.out.println("Subscribed successfully.");
          }
      
          @Override
          public void unSubscribe() {
              System.out.println("Unsubscribing " + userInfo + " to " + subject.subjectDetails() + " ...");
              this.subject.unSubscribeObserver(this);
              System.out.println("Unsubscribed successfully.");
          }
      }
      

      上面的類(lèi)是實(shí)現(xiàn)觀(guān)察者接口的具體觀(guān)察者類(lèi)。它還存儲(chǔ)對(duì)它訂閱的主題的引用,并可選地存儲(chǔ)用于顯示用戶(hù)信息的userInfo變量∨翱椋現(xiàn)在俩滥,讓我們測(cè)試這個(gè)例子。

      public class TestObserver {
          public static void main(String[] args) {
              Subject subject = new CommentaryObject(new ArrayList<>(), "Soccer Match[2014AUG24]");
              Observer observer = new SMSUsers(subject, "Adam Warner [New York]");
              observer.subscribe();
              System.out.println();
              Observer observer2 = new SMSUsers(subject, "Tim Ronney [London]");
              observer2.subscribe();
              Commentary cObject = ((Commentary) subject);
              cObject.setDesc("Welcome to live Soccer match");
              cObject.setDesc("Current score 0-0");
              System.out.println();
              observer2.unSubscribe();
              System.out.println();
              cObject.setDesc("It’s a goal!!");
              cObject.setDesc("Current score 1-0");
              System.out.println();
              Observer observer3 = new SMSUsers(subject, "Marrie [Paris]");
              observer3.subscribe();
              System.out.println();
              cObject.setDesc("It’s another goal!!");
              cObject.setDesc("Half-time score 2-0");
          }
      }
      

      正如您所看到的贺奠,最初有兩個(gè)用戶(hù)訂閱了足球比賽并開(kāi)始接收評(píng)論霜旧。但是后來(lái)有一個(gè)用戶(hù)取消了訂閱,所以用戶(hù)沒(méi)有再收到評(píng)論儡率。然后挂据,另一個(gè)用戶(hù)訂閱并開(kāi)始獲得評(píng)論。所有這一切都在不改變現(xiàn)有代碼的情況下動(dòng)態(tài)發(fā)生儿普,不僅如此崎逃,假設(shè)公司想要在電子郵件上播放評(píng)論,或者任何其他公司想要與該公司合作來(lái)播放評(píng)論眉孩。您所需要做的就是創(chuàng)建兩個(gè)新類(lèi)个绍,如UserEmail和ColCompany。并通過(guò)實(shí)現(xiàn)observer接口使它們成為主題的觀(guān)察者勺像。只要主體知道它是一個(gè)觀(guān)察者障贸,它就會(huì)提供更新。

      4吟宦、何時(shí)使用觀(guān)察者模式篮洁?

      1. 當(dāng)抽象有兩個(gè)方面時(shí),一個(gè)依賴(lài)于另一個(gè)殃姓。將這些方面封裝在單獨(dú)的對(duì)象中袁波,可以獨(dú)立地改變和重用它們。
      2. 當(dāng)對(duì)一個(gè)對(duì)象的更改需要更改其他對(duì)象時(shí)蜗侈,您不知道需要更改多少對(duì)象篷牌。
      3. 當(dāng)一個(gè)對(duì)象應(yīng)該能夠通知其他對(duì)象而不需要假設(shè)這些對(duì)象是誰(shuí)時(shí)。換句話(huà)說(shuō)踏幻,您不希望這些對(duì)象緊密耦合枷颊。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市该面,隨后出現(xiàn)的幾起案子夭苗,更是在濱河造成了極大的恐慌,老刑警劉巖隔缀,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件题造,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡猾瘸,警方通過(guò)查閱死者的電腦和手機(jī)界赔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)丢习,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人淮悼,你說(shuō)我怎么就攤上這事咐低。” “怎么了敛惊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵渊鞋,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我瞧挤,道長(zhǎng)锡宋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任特恬,我火速辦了婚禮执俩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘癌刽。我一直安慰自己役首,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布显拜。 她就那樣靜靜地躺著衡奥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪远荠。 梳的紋絲不亂的頭發(fā)上矮固,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音譬淳,去河邊找鬼档址。 笑死,一個(gè)胖子當(dāng)著我的面吹牛邻梆,可吹牛的內(nèi)容都是我干的守伸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浦妄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尼摹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起剂娄,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窘问,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后宜咒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡把鉴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年故黑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了儿咱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡场晶,死狀恐怖混埠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诗轻,我是刑警寧澤钳宪,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站扳炬,受9級(jí)特大地震影響吏颖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恨樟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一半醉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧劝术,春花似錦缩多、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至绳泉,卻和暖如春逊抡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背圈纺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工秦忿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛾娶。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓灯谣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛔琅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胎许,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

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

  • 何時(shí)使用觀(guān)察者模式 1、觸發(fā)聯(lián)動(dòng):當(dāng)修改目標(biāo)狀態(tài)時(shí)就會(huì)觸發(fā)相應(yīng)的通知罗售,然后會(huì)循環(huán)調(diào)用所有注冊(cè)的觀(guān)察者對(duì)象的相應(yīng)方法...
    哥哥是歐巴Vitory閱讀 360評(píng)論 0 0
  • 設(shè)計(jì)模式分類(lèi) 總體來(lái)說(shuō)設(shè)計(jì)模式分為三大類(lèi):創(chuàng)建型模式辜窑,共五種:工廠(chǎng)方法模式、抽象工廠(chǎng)模式寨躁、單例模式穆碎、建造者模式、原...
    lifeline丿毅閱讀 1,202評(píng)論 0 2
  • 定義 定義對(duì)象之間一對(duì)多的依賴(lài)關(guān)系职恳,使得每當(dāng)一個(gè)對(duì)象發(fā)生變化時(shí)所禀,則所有依賴(lài)于它的對(duì)象都會(huì)得到通知并自動(dòng)更新方面。這個(gè)模...
    m1Ku閱讀 200評(píng)論 0 1
  • 當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀(guān)察者模式(Observer Pattern)色徘。比如恭金,當(dāng)一個(gè)對(duì)象被修改時(shí),則...
    哈哈撒拉嘿閱讀 391評(píng)論 0 0
  • (一)手繪地圖 桌面放著那本手繪地圖 那是我花了好多個(gè) 喝咖啡的夜晚 描好的旅行線(xiàn)路 只是為了一個(gè)遙遠(yuǎn)的美好 與你...
    海明子閱讀 433評(píng)論 0 4