<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「補課」進(jìn)行時:設(shè)計模式(15)——觀察者模式

          共 8078字,需瀏覽 17分鐘

           ·

          2020-12-02 11:22

          1. 前文匯總

          「補課」進(jìn)行時:設(shè)計模式系列

          2. 觀察者模式

          2.1 定義

          觀察者模式(Observer Pattern)也叫做發(fā)布訂閱模式(Publish/subscribe),它是一個在項目中經(jīng)常使用的模式,其定義如下:

          Define a one-to-many dependency between objects so that when oneobject changes state,all its dependents are notified and updatedautomatically.(定義對象間一種一對多的依賴關(guān)系,使得每當(dāng)一個對象改變狀態(tài),則所有依賴于它的對象都會得到通知并被自動更新。)

          2.2 通用類圖

          • Subject 被觀察者: 定義被觀察者必須實現(xiàn)的職責(zé),它必須能夠動態(tài)地增加、取消觀察者。它一般是抽象類或者是實現(xiàn)類,僅僅完成作為被觀察者必須實現(xiàn)的職責(zé):管理觀察者并通知觀察者。
          • ConcreteSubject 具體的被觀察者: 定義被觀察者自己的業(yè)務(wù)邏輯,同時定義對哪些事件進(jìn)行通知。
          • Observer 觀察者: 觀察者接收到消息后,即進(jìn)行update(更新方法)操作,對接收到的信息進(jìn)行處理。
          • ConcreteObserver 具體的觀察者: 每個觀察在接收到消息后的處理反應(yīng)是不同,各個觀察者有自己的處理邏輯。

          2.3 通用代碼

          Subject 被觀察者:

          public?abstract?class?Subject?{
          ????//?定義一個觀察者數(shù)組
          ????private?Vector?obsVector?=?new?Vector<>();
          ????//?添加一個觀察者
          ????public?void?addObserver(Observer?obsVector)?{
          ????????this.obsVector.add(obsVector);
          ????}
          ????//?刪除一個觀察者
          ????public?void?delObserver(Observer?observer)?{
          ????????this.obsVector.remove(observer);
          ????}
          ????//?通知所有觀察者
          ????public?void?notifyObservers()?{
          ????????for?(Observer?obs?:?this.obsVector)?{
          ????????????obs.update();
          ????????}
          ????}
          }

          ConcreteSubject 具體的被觀察者:

          public?class?ConcreteSubject?extends?Subject?{
          ????public?void?doSomething()?{
          ????????//?具體的業(yè)務(wù)
          ????????super.notifyObservers();
          ????}
          }

          Observer 觀察者:

          public?interface?Observer?{
          ????void?update();
          }

          ConcreteObserver 具體的觀察者:

          public?class?ConcreteObserver?implements?Observer{
          ????@Override
          ????public?void?update()?{
          ????????System.out.println("進(jìn)行消息處理");
          ????}
          }

          測試場景類:

          public?class?Test?{
          ????public?static?void?main(String[]?args)?{
          ????????//?創(chuàng)建一個被觀察者
          ????????ConcreteSubject?subject?=?new?ConcreteSubject();
          ????????//?創(chuàng)建一個觀察者
          ????????Observer?observer?=?new?ConcreteObserver();
          ????????//?觀察者觀察被觀察者
          ????????subject.addObserver(observer);
          ????????//?觀察者開始活動了
          ????????subject.doSomething();
          ????}
          }

          3. 一個案例

          觀察者模式是設(shè)計模式中的超級模式,有關(guān)他的應(yīng)用隨處可見。

          就比如說微信公眾號,我每天推送一篇博文內(nèi)容,訂閱的用戶都能夠在我發(fā)布推送之后及時接收到推送,方便地在手機端進(jìn)行閱讀。

          訂閱者接口(觀察者)

          public?interface?Subscriber?{
          ????void?receive(String?publisher,?String?articleName);
          }

          微信客戶端(具體觀察者)

          public?class?WeChatClient?implements?Subscriber?{

          ????private?String?username;

          ????public?WeChatClient(String?username)?{
          ????????this.username?=?username;
          ????}

          ????@Override
          ????public?void?receive(String?publisher,?String?articleName)?{
          ????????System.out.println(String.format("用戶<%s>?接收到?<%s>微信公眾號?的推送,文章標(biāo)題為?<%s>",?username,?publisher,?articleName));
          ????}
          }

          一個微信客戶端(具體觀察者)

          public?class?Publisher?{
          ????private?List?subscribers;
          ????private?boolean?pubStatus?=?false;

          ????public?Publisher()?{
          ????????subscribers?=?new?ArrayList<>();
          ????}

          ????protected?void?subscribe(Subscriber?subscriber)?{
          ????????this.subscribers.add(subscriber);
          ????}

          ????protected?void?unsubscribe(Subscriber?subscriber)?{
          ????????if?(this.subscribers.contains(subscriber))?{
          ????????????this.subscribers.remove(subscriber);
          ????????}
          ????}

          ????protected?void?notifySubscribers(String?publisher,?String?articleName)?{
          ????????if?(this.pubStatus?==?false)?{
          ????????????return;
          ????????}
          ????????for?(Subscriber?subscriber?:?this.subscribers)?{
          ????????????subscriber.receive(publisher,?articleName);
          ????????}
          ????????this.clearPubStatus();
          ????}

          ????protected?void?setPubStatus()?{
          ????????this.pubStatus?=?true;
          ????}

          ????protected?void?clearPubStatus()?{
          ????????this.pubStatus?=?false;
          ????}
          }

          具體目標(biāo)

          public?class?WeChatAccounts?extends?Publisher?{
          ????private?String?name;

          ????public?WeChatAccounts(String?name)?{
          ????????this.name?=?name;
          ????}

          ????public?void?publishArticles(String?articleName,?String?content)?{
          ????????System.out.println(String.format("\n<%s>微信公眾號?發(fā)布了一篇推送,文章名稱為?<%s>,內(nèi)容為?<%s>?",?this.name,?articleName,?content));
          ????????setPubStatus();
          ????????notifySubscribers(this.name,?articleName);
          ????}
          }

          測試類

          public?class?Test?{
          ????public?static?void?main(String[]?args)?{
          ????????WeChatAccounts?accounts?=?new?WeChatAccounts("極客挖掘機");

          ????????WeChatClient?user1?=?new?WeChatClient("張三");
          ????????WeChatClient?user2?=?new?WeChatClient("李四");
          ????????WeChatClient?user3?=?new?WeChatClient("王五");

          ????????accounts.subscribe(user1);
          ????????accounts.subscribe(user2);
          ????????accounts.subscribe(user3);

          ????????accounts.publishArticles("設(shè)計模式?|?觀察者模式及典型應(yīng)用",?"觀察者模式的內(nèi)容...");

          ????????accounts.unsubscribe(user1);
          ????????accounts.publishArticles("設(shè)計模式?|?單例模式及典型應(yīng)用",?"單例模式的內(nèi)容....");
          ????}
          }

          測試結(jié)果

          <極客挖掘機>微信公眾號?發(fā)布了一篇推送,文章名稱為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>,內(nèi)容為?<觀察者模式的內(nèi)容...>?
          用戶<張三>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>
          用戶<李四>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>
          用戶<王五>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>

          <極客挖掘機>微信公眾號?發(fā)布了一篇推送,文章名稱為?<設(shè)計模式?|?單例模式及典型應(yīng)用>,內(nèi)容為?<單例模式的內(nèi)容....>?
          用戶<李四>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?單例模式及典型應(yīng)用>
          用戶<王五>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?單例模式及典型應(yīng)用>

          4. JDK 對的觀察者模式的支持

          觀察者模式在 Java 語言中的地位非常重要。在 JDK 的 java.util 包中,提供了 Observable 類以及 Observer 接口,它們構(gòu)成了JDK對觀察者模式的支持。

          java.util.Observer 接口中,僅有一個 update(Observable o, Object arg) 方法,當(dāng)觀察目標(biāo)發(fā)生變化時被調(diào)用:

          public?interface?Observer?{
          ????void?update(Observable?o,?Object?arg);
          }

          java.util.Observable 類則為目標(biāo)類:

          public?class?Observable?{
          ????private?boolean?changed?=?false;
          ????private?Vector?obs;

          ????public?Observable()?{
          ????????obs?=?new?Vector<>();
          ????}
          ????//?用于注冊新的觀察者對象到向量中
          ????public?synchronized?void?addObserver(Observer?o)?{
          ????????if?(o?==?null)
          ????????????throw?new?NullPointerException();
          ????????if?(!obs.contains(o))?{
          ????????????obs.addElement(o);
          ????????}
          ????}
          ????//?用于刪除向量中的某一個觀察者對象
          ????public?synchronized?void?deleteObserver(Observer?o)?{
          ????????obs.removeElement(o);
          ????}

          ????public?void?notifyObservers()?{
          ????????notifyObservers(null);
          ????}
          ????//?通知方法,用于在方法內(nèi)部循環(huán)調(diào)用向量中每一個觀察者的update()方法
          ????public?void?notifyObservers(Object?arg)?{
          ????????Object[]?arrLocal;

          ????????synchronized?(this)?{
          ????????????if?(!changed)
          ????????????????return;
          ????????????arrLocal?=?obs.toArray();
          ????????????clearChanged();
          ????????}

          ????????for?(int?i?=?arrLocal.length-1;?i>=0;?i--)
          ????????????((Observer)arrLocal[i]).update(this,?arg);
          ????}
          ????//?用于清空向量,即刪除向量中所有觀察者對象
          ????public?synchronized?void?deleteObservers()?{
          ????????obs.removeAllElements();
          ????}
          ????//?該方法被調(diào)用后會設(shè)置一個boolean類型的內(nèi)部標(biāo)記變量changed的值為true,表示觀察目標(biāo)對象的狀態(tài)發(fā)生了變化
          ????protected?synchronized?void?setChanged()?{
          ????????changed?=?true;
          ????}
          ????//?用于將changed變量的值設(shè)為false,表示對象狀態(tài)不再發(fā)生改變或者已經(jīng)通知了所有的觀察者對象,調(diào)用了它們的update()方法
          ????protected?synchronized?void?clearChanged()?{
          ????????changed?=?false;
          ????}
          ????//?返回對象狀態(tài)是否改變
          ????public?synchronized?boolean?hasChanged()?{
          ????????return?changed;
          ????}
          ????//?返回向量中觀察者的數(shù)量
          ????public?synchronized?int?countObservers()?{
          ????????return?obs.size();
          ????}
          }

          相比較我們自己的示例 Publisherjava.util.Observer 中多了并發(fā)和 NPE 方面的考慮 。

          使用 JDK 對觀察者模式的支持,改寫一下上面的示例:

          增加一個通知類 WechatNotice ,用于推送通知的傳遞:

          public?class?WechatNotice?{
          ????private?String?publisher;
          ????private?String?articleName;
          ????//?省略?get/set
          }

          然后改寫 WeChatClientWeChatAccounts ,分別實現(xiàn) JDK 的 Observer 接口和繼承 Observable 類:

          public?class?WeChatClient?implements?Observer?{

          ????private?String?username;

          ????public?WeChatClient(String?username)?{
          ????????this.username?=?username;
          ????}

          ????@Override
          ????public?void?update(Observable?o,?Object?arg)?{
          ????????WechatNotice?notice?=?(WechatNotice)?arg;
          ????????System.out.println(String.format("用戶<%s>?接收到?<%s>微信公眾號?的推送,文章標(biāo)題為?<%s>",?username,?notice.getPublisher(),?notice.getArticleName()));
          ????}
          }

          public?class?WeChatAccounts?extends?Observable?{
          ????private?String?name;

          ????public?WeChatAccounts(String?name)?{
          ????????this.name?=?name;
          ????}

          ????public?void?publishArticles(String?articleName,?String?content)?{
          ????????System.out.println(String.format("\n<%s>微信公眾號?發(fā)布了一篇推送,文章名稱為?<%s>,內(nèi)容為?<%s>?",?this.name,?articleName,?content));
          ????????setChanged();
          ????????notifyObservers(new?WechatNotice(this.name,?articleName));
          ????}
          }

          最后是一個測試類:

          public?class?Test?{
          ????public?static?void?main(String[]?args)?{
          ????????WeChatAccounts?accounts?=?new?WeChatAccounts("極客挖掘機");

          ????????WeChatClient?user1?=?new?WeChatClient("張三");
          ????????WeChatClient?user2?=?new?WeChatClient("李四");
          ????????WeChatClient?user3?=?new?WeChatClient("王五");

          ????????accounts.addObserver(user1);
          ????????accounts.addObserver(user2);
          ????????accounts.addObserver(user3);

          ????????accounts.publishArticles("設(shè)計模式?|?觀察者模式及典型應(yīng)用",?"觀察者模式的內(nèi)容...");

          ????????accounts.deleteObserver(user1);
          ????????accounts.publishArticles("設(shè)計模式?|?單例模式及典型應(yīng)用",?"單例模式的內(nèi)容....");
          ????}
          }

          測試結(jié)果:

          <極客挖掘機>微信公眾號?發(fā)布了一篇推送,文章名稱為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>,內(nèi)容為?<觀察者模式的內(nèi)容...>?
          用戶<王五>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>
          用戶<李四>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>
          用戶<張三>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?觀察者模式及典型應(yīng)用>

          <極客挖掘機>微信公眾號?發(fā)布了一篇推送,文章名稱為?<設(shè)計模式?|?單例模式及典型應(yīng)用>,內(nèi)容為?<單例模式的內(nèi)容....>?
          用戶<王五>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?單例模式及典型應(yīng)用>
          用戶<李四>?接收到?<極客挖掘機>微信公眾號?的推送,文章標(biāo)題為?<設(shè)計模式?|?單例模式及典型應(yīng)用>

          和前面的示例結(jié)果完全一致。





          感謝閱讀



          瀏覽 40
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费搞黄网站。 | 日批黄色| 亚洲欧美v在线视频 | 中文字幕操逼片 | 91干伦理片 |