<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>

          設(shè)計模式詳解——觀察者模式

          共 4261字,需瀏覽 9分鐘

           ·

          2021-10-16 15:33

          前言

          今天我們來看下一個可以有效實現(xiàn)松耦合的設(shè)計模式——觀察者模式,這個設(shè)計模式我之前也僅僅停留在聽說過的層面,關(guān)于它的具體實現(xiàn)更是一知半解,所以今天我們就來簡單剖析下這個設(shè)計模式。

          設(shè)計模式

          觀察者模式

          觀察者模式定義了對象之間的一對多依賴,當一個對象改變狀態(tài)時,它的所有依賴者都會收到通知并自動更新。

          要點
          • 觀察者模式定義了對象之間一對多的關(guān)系
          • 主題(可觀察者)用一個共同的接口來更新觀察者
          • 觀察者和可觀察者之間用松耦合方式結(jié)合,可觀察者不知道觀察者的細節(jié),只知道觀察者實現(xiàn)了觀察者接口
          • 使用次模式時,你可以從被觀察者處推或拉數(shù)據(jù)(推的方式被認為是更正確的)
          • 有多個觀察者時,不可以依賴特定的通知次序
          • java中有多種觀察者模式的實現(xiàn),包括了通用的java.util.Observable,不過需要注意Observable實現(xiàn)上所帶來的問題,有必要的話,可以實現(xiàn)自己的Observable
          • Swing大量使用觀察者模式,許多GUI框架也是如此
          • 觀察者模式還廣泛被應用在許多地方,比如:JavaBeansRMI
          示例

          下面我們以一個具體實例,來展示下觀察者模式的具體實現(xiàn)。這里我們就直接以《Head First設(shè)計模式》中的氣象站為例,其中天氣信息就表示被觀察者,天氣布告板就表示訂閱者和觀察者,當天氣發(fā)生變化(被觀察者)時,會通過notifyObserver通知所有觀察者,并調(diào)用他們的控制方法處理數(shù)據(jù)。下面我們就來看下具體實現(xiàn)過程

          被觀察者接口接口

          這里有三個方法,第一個是注冊觀察者,第二個是移除觀察者,第三個是通知觀察者

          public?interface?Subject?{
          ????void?registerObserver(Observer?observer);
          ????void?removeObserver(Observer?observer);
          ????void?notifyObserver();
          }
          觀察者接口

          觀察者接口就一個方法,主要用于更新從被觀察者中獲取到的數(shù)據(jù),該方法會在被注冊者的notifyObserver方法中被調(diào)用

          public?interface?Observer?{
          ????void?update(float?temp,?float?humidity,?float?pressure);
          }
          控制層接口

          這個接口主要是用于處理被觀察者更新的數(shù)據(jù),核心方法就一個。

          public?interface?DisplayElement?{
          ????void?display();
          }
          被觀察者實現(xiàn)

          這里是被觀察者的具體實現(xiàn),被觀察者也可以叫數(shù)據(jù)源,當數(shù)據(jù)發(fā)生變化時,由它負責告知觀察者。

          public?class?WeatherData?implements?Subject?{
          ????private?List?observerList;
          ????private?float?temp;
          ????private?float?humidity;
          ????private?float?pressure;

          ????public?WeatherData(List?observerList)?{
          ????????this.observerList?=?observerList;
          ????}

          ????@Override
          ????public?void?registerObserver(Observer?observer)?{
          ????????observerList.add(observer);
          ????}

          ????@Override
          ????public?void?removeObserver(Observer?observer)?{
          ????????observerList.remove(observer);
          ????}

          ????@Override
          ????public?void?notifyObserver()?{
          ????????observerList.forEach(observer?->?observer.update(temp,?humidity,?pressure));
          ????}

          ????public?void?measurementChanged()?{
          ????????notifyObserver();
          ????}

          ????public?void?setMeasurements(float?temp,?float?humidity,?float?pressure)?{
          ????????this.temp?=?temp;
          ????????this.humidity?=?humidity;
          ????????this.pressure?=?pressure;
          ????????measurementChanged();
          ????}
          }
          觀察者實現(xiàn)

          觀察者我們實現(xiàn)了兩個,主要是便于后面測試。這兩個實現(xiàn)處理名字不一樣,其他代碼都是一樣的。

          public?class?RemoteDisplay?implements?Observer,?DisplayElement?{

          ????private?Subject?subject;
          ????private?float?temp;
          ????private?float?humidity;
          ????private?float?pressure;

          ????public?RemoteDisplay(Subject?subject)?{
          ????????this.subject?=?subject;
          ????????subject.registerObserver(this);
          ????}

          ????@Override
          ????public?void?display()?{
          ????????System.out.println(String.format("=======?\nname:%s?\ntemp:%S?\nhumidity:%s?\npressure:%s",?"remote",?temp,?humidity,?pressure));
          ????}

          ????@Override
          ????public?void?update(float?temp,?float?humidity,?float?pressure)?{
          ????????this.temp?=?temp;
          ????????this.humidity?=?humidity;
          ????????this.pressure?=?pressure;
          ????????display();
          ????}
          }

          public?class?CurrentWeatherDataDisplay?implements?Observer,?DisplayElement?{

          ????private?Subject?subject;
          ????private?float?temp;
          ????private?float?humidity;
          ????private?float?pressure;

          ????public?CurrentWeatherDataDisplay(Subject?subject)?{
          ????????this.subject?=?subject;
          ????????subject.registerObserver(this);
          ????}

          ????@Override
          ????public?void?display()?{
          ????????System.out.println(String.format("=======?\nname:%s?\ntemp:%S?\nhumidity:%s?\npressure:%s",?"urrentWeatherData",?temp,?humidity,?pressure));
          ????}

          ????@Override
          ????public?void?update(float?temp,?float?humidity,?float?pressure)?{
          ????????this.temp?=?temp;
          ????????this.humidity?=?humidity;
          ????????this.pressure?=?pressure;
          ????????display();
          ????}
          }
          測試代碼

          從上面觀察者的實現(xiàn)類中,我們可以看出來,在實例化觀察者的時候,其實已經(jīng)完成了注冊操作,所以這里我們不再需要手動注冊觀察者,后面再被觀察者(數(shù)據(jù))發(fā)生變化時,觀察者會實時被通知。

          @Test
          ????public?void?testWeatherDisplay()?{
          ????????WeatherData?data?=?new?WeatherData(new?ArrayList<>());
          ????????new?CurrentWeatherDataDisplay(data);
          ????????new?RemoteDisplay(data);
          ????????data.setMeasurements(12,?88,?981);
          ????????System.out.println("----------------分割線------------------");
          ????????data.setMeasurements(28,?68,?871);
          ????????System.out.println("----------------分割線------------------");
          ????????data.setMeasurements(38,?48,?681);
          ????}
          運作結(jié)果

          總結(jié)

          從實例的運行結(jié)果來看,觀察者模式特別適用于那些一對多的應用場景,比如數(shù)據(jù)推送同步,當你的平臺數(shù)量發(fā)生變化時,數(shù)據(jù)發(fā)送方只需要將相關(guān)平臺注冊或刪除,即可完成觀察者的變更,可以實現(xiàn)代碼之間的松耦合,提升代碼的擴展性。

          與這個設(shè)計模式類似的設(shè)計模式是訂閱者模式,這兩種設(shè)計模式,在我之前的認知中,我覺得他們應該是一樣的,但是今天查閱了相關(guān)資料之后,發(fā)現(xiàn)它們并不完全一樣,這里我們先大概對訂閱者模式有一個基本的認知,后面等我們分享完訂閱者模式之后,我們再來比較這兩個的區(qū)別。

          - END -


          瀏覽 44
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  神马午夜性爱 | 风流少妇一区二区三区91 | 黄色免费网页 | 日韩欧美中文在线无线码视频在线看免费版 | 看小逼逼在线 |