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

觀察者模式原理

Internet氣象站項(xiàng)目富雅,普通的OO設(shè)計(jì)方案有問(wèn)題掸驱。

  1. Internet氣象站項(xiàng)目:
  • 提供溫度、氣壓和濕度的接口
  • 測(cè)量數(shù)據(jù)更新時(shí)需試試通知給第三方
  • 需要設(shè)計(jì)開(kāi)放型API没佑,便于其他第三方公司也能接入氣象站獲取數(shù)據(jù)
  1. WeatherData類(lèi)
B0A20A52-5606-4344-B078-82D3A9C053FF.png

在第三方獲取數(shù)據(jù)的時(shí)候毕贼,datachange()函數(shù)里就要去通知相應(yīng)的類(lèi),造成一個(gè)代碼的重復(fù)蛤奢。那么在這里的一個(gè)解決的辦法就是將被通知的類(lèi)抽象鬼癣,在氣象站類(lèi)里進(jìn)行注冊(cè),氣象站會(huì)向在列表中的對(duì)象發(fā)放通知提醒啤贩,這樣氣象站就不需要重新編譯停下來(lái)待秃。


211B655D-BD17-4C77-9431-2C5421F3A292.png

原理

  1. 觀察者模式就像定牛奶
  • 奶站 subject
  • 用戶 observer
  1. Subject:登記注冊(cè)、移除和通知
F4EA6556-2133-4F57-83D9-46CF413EC995.png
  1. Observer:接收輸入
889781EC-20AE-4888-959F-3394B92C9C97.png
  1. 觀察者模式:對(duì)象之間多對(duì)一依賴的一種設(shè)計(jì)方案痹屹,被依賴的對(duì)象為Subject章郁,依賴的對(duì)象為Observer,Subject通知Observer變化痢掠。

用觀察者重新設(shè)計(jì)的方案

A96C1550-CA4F-43C6-91C6-66FAC34DA0F6.png

首先定義subject接口驱犹,用于注冊(cè)刪除通知其他觀察者

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}

然后定義Observer接口,用于接收更新的數(shù)據(jù)

public interface Observer {
    public void update(float mTemperatrue,float mPressure,float mHumidity);
}

定義subject的氣象站實(shí)現(xiàn)類(lèi) 用于發(fā)送數(shù)據(jù) 注冊(cè)觀察者
在這里用了一個(gè)ArrayList數(shù)組來(lái)保存觀察者足画,相當(dāng)于一個(gè)注冊(cè)表的功能

public class WeatherDataSt implements Subject{
    
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    private ArrayList<Observer> mObservers;
    public WeatherDataSt()
    {
        mObservers=new ArrayList<Observer>();
    }
    
    public float getTemperature()
    {
        return mTemperatrue;
        
    }
    
    public float getPressure()
    {
        return mPressure;
        
    }
    
    public float getHumidity()
    {
        return mHumidity;
        
    }
    public void dataChange()
    {
        notifyObservers();
    }

    

    
    
    
    public void setData(float mTemperatrue,float mPressure,float mHumidity)
    {
        this.mTemperatrue=mTemperatrue;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        dataChange();
    }

    @Override
    public void registerObserver(Observer o) {
        // TODO Auto-generated method stub
        mObservers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        // TODO Auto-generated method stub
        if(mObservers.contains(o))
        {mObservers.remove(o);}
    }

    @Override
    public void notifyObservers() {
        // TODO Auto-generated method stub
        for(int i=0,len=mObservers.size();i<len;i++)
        {
            mObservers.get(i).update(getTemperature(), getPressure(), getHumidity());
        }
    }

}

定義兩個(gè)觀察者實(shí)現(xiàn)類(lèi)雄驹,update用于接收數(shù)據(jù),display用于打印

public class ForcastConditions implements Observer{
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    @Override
    public void update(float mTemperatrue, float mPressure, float mHumidity) {
        // TODO Auto-generated method stub
        this.mTemperatrue=mTemperatrue;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        
        display();
    }
    public void display()
    {
        System.out.println("**明天溫度:"+(mTemperatrue+Math.random())+"**");
        System.out.println("**明天氣壓:"+(mPressure+10*Math.random())+"**");
        System.out.println("**明天濕度:"+(mHumidity+Math.random())+"**");
    }
}

public class CurrentConditions implements Observer {

    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;

    @Override
    public void update(float mTemperatrue, float mPressure, float mHumidity) {
        // TODO Auto-generated method stub
        this.mHumidity = mHumidity;
        this.mPressure = mPressure;
        this.mTemperatrue = mTemperatrue;
        display();
    }
    public void display() {
        System.out.println("***Today mTemperatrue:" + mTemperatrue + "***");
        System.out.println("***Today mPressure:" + mPressure + "***");
        System.out.println("***Today mHumidity:" + mHumidity + "***");
    }
}

下民是一個(gè)測(cè)試類(lèi)

public class InternetWeather {

    public static void main(String[] args) {
        
        CurrentConditions mCurrentConditions;
        ForcastConditions mForcastConditions;
        WeatherDataSt mWeatherDataSt;
        
        mWeatherDataSt=new WeatherDataSt();
        mCurrentConditions=new CurrentConditions();
        mForcastConditions=new ForcastConditions();
        
        mWeatherDataSt.registerObserver(mCurrentConditions);
        mWeatherDataSt.registerObserver(mForcastConditions);
        
        mWeatherDataSt.setData(30, 150, 40);
        mWeatherDataSt.removeObserver(mCurrentConditions);
        mWeatherDataSt.setData(40, 250, 50);
    }
}

其實(shí)觀察者模式的想法就是基于插銷(xiāo)原理淹辞,實(shí)現(xiàn)一個(gè)主類(lèi)一直運(yùn)行医舆,然后獲取數(shù)據(jù)的接口類(lèi)一個(gè)可插拔解耦。

Java中的觀察者模式

Java中其實(shí)也有已經(jīng)實(shí)現(xiàn)的觀察者的類(lèi)象缀,那么subject類(lèi)集成Observable類(lèi)蔬将,變成一個(gè)主站,其他兩個(gè)接收數(shù)據(jù)的子類(lèi)實(shí)現(xiàn)Observer接口央星,成為一個(gè)觀察者霞怀,主站可以調(diào)用nofityObservers方法來(lái)通知觀察者。那么觀察者這里接收數(shù)據(jù)莉给,java給了兩個(gè)選擇毙石,一種是主站推數(shù)據(jù),一種是觀察者拉數(shù)據(jù)颓遏,選擇自己需要的數(shù)據(jù)進(jìn)行獲取徐矩。
下面貼出示例代碼 不做解釋

public class WeatherData extends Observable{
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    
    public float getTemperature()
    {
        return mTemperatrue;
        
    }
    
    public float getPressure()
    {
        return mPressure;
        
    }
    
    public float getHumidity()
    {
        return mHumidity;
        
    }
    
    
    public void dataChange()
    {
        this.setChanged();
        this.notifyObservers(new Data(getTemperature(),getPressure(),getHumidity()));
        
    }
    
    
    public void setData(float mTemperatrue,float mPressure,float mHumidity)
    {
        this.mTemperatrue=mTemperatrue;
        this.mPressure=mPressure;
        this.mHumidity=mHumidity;
        dataChange();
    }
    
    public class Data
    {
        public float mTemperatrue;
        public float mPressure;
        public float mHumidity;
        public Data(float mTemperatrue,float mPressure,float mHumidity)
        {
            this.mTemperatrue=mTemperatrue;
            this.mPressure=mPressure;
            this.mHumidity=mHumidity;
        }
    }
    
}

public class ForcastConditions implements Observer  {
    
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    @Override
    public void update(Observable arg0, Object arg1) {
        // TODO Auto-generated method stub
        this.mTemperatrue=((Data)(arg1)).mTemperatrue;
        this.mPressure=((Data)(arg1)).mPressure;
        this.mHumidity=((Data)(arg1)).mHumidity;
        display();
    }
    
    public void display()
    {
        System.out.println("***Tomorrow mTemperatrue:" +(mTemperatrue+1)+"***");
        System.out.println("***Tomorrow mPressure:" +(mPressure+1)+"***");
        System.out.println("***Tomorrow mHumidity:" +(mHumidity+1)+"***");
    }
    
    
}
public class ForcastConditions implements Observer  {
    
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    @Override
    public void update(Observable arg0, Object arg1) {
        // TODO Auto-generated method stub
        this.mTemperatrue=((Data)(arg1)).mTemperatrue;
        this.mPressure=((Data)(arg1)).mPressure;
        this.mHumidity=((Data)(arg1)).mHumidity;
        display();
    }
    
    public void display()
    {
        System.out.println("***Tomorrow mTemperatrue:" +(mTemperatrue+1)+"***");
        System.out.println("***Tomorrow mPressure:" +(mPressure+1)+"***");
        System.out.println("***Tomorrow mHumidity:" +(mHumidity+1)+"***");
    }
}
public class CurrentConditions implements Observer {
    
    private float mTemperatrue;
    private float mPressure;
    private float mHumidity;
    @Override
    public void update(Observable arg0, Object arg1) {
        // TODO Auto-generated method stub
        this.mTemperatrue=((Data)(arg1)).mTemperatrue;
        this.mPressure=((Data)(arg1)).mPressure;
        this.mHumidity=((Data)(arg1)).mHumidity;
        display();
    }
    
    public void display()
    {
        System.out.println("***Today mTemperatrue:" +mTemperatrue+"***");
        System.out.println("***Today mPressure:" +mPressure+"***");
        System.out.println("***Today mHumidity:" +mHumidity+"***");
    }   
}
public class InternetWeather {
    public static void main(String[] args) {
        CurrentConditions mCurrentConditions;
        ForcastConditions mForcastConditions;
        WeatherData mWeatherData;
         
        mCurrentConditions=new CurrentConditions();
        mForcastConditions=new ForcastConditions();
        mWeatherData=new WeatherData();
        
        mWeatherData.addObserver(mCurrentConditions);
        mWeatherData.addObserver(mForcastConditions);
        mWeatherData.setData(30, 150, 40);
        
        mWeatherData.deleteObserver(mCurrentConditions);
        mWeatherData.setData(35, 150, 60);
        
    }
}

觀察者模式關(guān)鍵點(diǎn)

  • 松耦合 高內(nèi)聚 隔離影響
  • java內(nèi)置觀察者使用注意點(diǎn)。Observable是一個(gè)類(lèi)叁幢,只能繼承滤灯,而java又是單繼承的,所以要注意這一點(diǎn)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鳞骤,一起剝皮案震驚了整個(gè)濱河市窒百,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌豫尽,老刑警劉巖贝咙,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拂募,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)窟她,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)陈症,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人震糖,你說(shuō)我怎么就攤上這事录肯。” “怎么了吊说?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵论咏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我颁井,道長(zhǎng)厅贪,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任雅宾,我火速辦了婚禮养涮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘眉抬。我一直安慰自己贯吓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布蜀变。 她就那樣靜靜地躺著悄谐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪库北。 梳的紋絲不亂的頭發(fā)上爬舰,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音贤惯,去河邊找鬼洼专。 笑死,一個(gè)胖子當(dāng)著我的面吹牛孵构,可吹牛的內(nèi)容都是我干的屁商。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蜡镶!你這毒婦竟也來(lái)了雾袱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤官还,失蹤者是張志新(化名)和其女友劉穎芹橡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體望伦,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡林说,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屯伞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腿箩。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖劣摇,靈堂內(nèi)的尸體忽然破棺而出珠移,到底是詐尸還是另有隱情,我是刑警寧澤末融,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布叮贩,位于F島的核電站镜遣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酷誓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一泽示、第九天 我趴在偏房一處隱蔽的房頂上張望抱慌。 院中可真熱鬧霜威,春花似錦、人聲如沸粹舵。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)眼滤。三九已至巴席,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诅需,已是汗流浹背漾唉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留堰塌,地道東北人赵刑。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像场刑,于是被迫代替她去往敵國(guó)和親般此。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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