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

        共 4261字,需瀏覽 9分鐘

         ·

        2021-10-16 15:33

        前言

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

        設(shè)計模式

        觀察者模式

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

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

        下面我們以一個具體實例,來展示下觀察者模式的具體實現(xiàn)。這里我們就直接以《Head First設(shè)計模式》中的氣象站為例,其中天氣信息就表示被觀察者,天氣布告板就表示訂閱者和觀察者,當(dāng)天氣發(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ù)源,當(dāng)數(shù)據(jù)發(fā)生變化時,由它負(fù)責(zé)告知觀察者。

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

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

        - END -


        瀏覽 44
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
          
          

            1. 一边揉美女胸一边摸屁股 | 丰满女老板大胸老板bd高清 | 国产女人18毛片水18精品软件 | 女人扒开尿口让男人舔 | 国产一级a一级a毛片视频黑人 |