設(shè)計(jì)模式之觀察者模式(行為型)

模式定義

觀察者模式(Observer Pattern):觀察者模式定義對(duì)象間的一種一對(duì)多依賴關(guān)系赚爵,使得每當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴的對(duì)象皆得到通知并且被自動(dòng)更新粟耻。不過觀察者只能知道目標(biāo)發(fā)送了改變试读,而不能知道具體怎么改變的。

觀察者角色

觀察者模式包含如下角色:

Subject:目標(biāo)

ConcreteSubject:具體目標(biāo)

Observer:觀察者

ConcreteObserver:具體觀察者

Observer模式”push”和”pull”數(shù)據(jù)

具體Subject可以通過兩種方式通知具體觀察者更新數(shù)據(jù):

①push數(shù)據(jù)方式:具體Subject將變化后的數(shù)據(jù)全部交給具體觀察者;

②pull數(shù)據(jù)方式:具體Subject提供獲得數(shù)據(jù)的方法,具體觀察者調(diào)用具體主題提供的方法獲得數(shù)據(jù)训裆。

典型列子

PS:代碼例子來自《圖說設(shè)計(jì)模式》

抽象目標(biāo)類

import java.util.*;
public abstract class Subject
{
            protected ArrayList observers = new ArrayList();
    public abstract void attach(Observer observer);
    public abstract void detach(Observer observer);
    public abstract void notify();
} 

具體目標(biāo)類

public class ConcreteSubject extends Subject
{
    public void attach(Observer observer)
    {
        observers.add(observer);
    }
    
    public void detach(Observer observer)
    {
        observers.remove(observer);
    }
    
    public void notify()
    {
        for(Object obs:observers)
        {
            ((Observer)obs).update();
        }
    }   
} 

抽象觀察者類

public interface Observer
{
    public void update();
} 

具體觀察者類

public class ConcreteObserver implements Observer
{
    public void update()
    {
        //具體更新代碼
    }
} 

還有一個(gè)不錯(cuò)的例子可以參考《Head First 設(shè)計(jì)模式》里的氣象局例子

模式優(yōu)缺點(diǎn)

觀察者優(yōu)點(diǎn):下面簡(jiǎn)要描述一下,觀察者可以實(shí)現(xiàn)表現(xiàn)層和數(shù)據(jù)邏輯層的分離蜀铲;觀察者模式在觀察目標(biāo)和觀察者之間建立一個(gè)抽象的耦合

觀察者缺點(diǎn):如果觀察者類和目標(biāo)類之間有循環(huán)關(guān)聯(lián)边琉,很容易導(dǎo)致系統(tǒng)奔潰;如果觀察者太多的話记劝,通知所有的觀察者將花費(fèi)很多時(shí)間

模式應(yīng)用

Swing变姨、RMI、JDK內(nèi)置的java.util.Observer接口和java.util.Observable類都是觀察者模式的應(yīng)用

經(jīng)典氣象局例子

PS:本列子來自《Head First 設(shè)計(jì)模式》
自己看《Head First設(shè)計(jì)模式》厌丑,本博客僅僅是自己做做筆記
下面的例子來自《Head First設(shè)計(jì)模式》一書定欧,推薦讀者去學(xué)習(xí)
[圖片上傳失敗...(image-e24d0-1532252388825)]

主題接口,定義一個(gè)主題接口


public interface Subject {
    //注冊(cè)觀察者
    public void registerObserver(Observer o);
    //remove觀察者
    public void removeObserver(Observer o);
    //通知觀察者
    public void notifyObservers();
}

weatherDate類怒竿,其實(shí)就是主題接口的實(shí)現(xiàn)類砍鸠,weatherData類實(shí)現(xiàn)Subject接口,主要用來注冊(cè)觀察者耕驰,通知觀察者等等爷辱,當(dāng)數(shù)據(jù)變化時(shí),即時(shí)通知注冊(cè)的觀察者,代碼實(shí)現(xiàn)是通過循環(huán)遍歷饭弓,觀察者再調(diào)用更新數(shù)據(jù)接口來實(shí)現(xiàn)双饥,《Head First設(shè)計(jì)模式》一書提供了基于JDK的內(nèi)置類來實(shí)現(xiàn)的列子,讀者可以去看看


import java.util.ArrayList;

public class WeatherData implements Subject {
    private ArrayList observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList();//實(shí)例對(duì)象弟断,通過數(shù)組列表來存在觀察者對(duì)象
    }

    public void registerObserver(Observer o) {
        observers.add(o);//注冊(cè)觀察者
    }

    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);//remove觀察者對(duì)象
        }
    }

    public void notifyObservers() {//循環(huán)遍歷咏花,通知所有注冊(cè)的觀察者
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = (Observer)observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    // other WeatherData methods here

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}

觀察者接口類

public interface Observer {
    public void update(float temp, float humidity, float pressure);
}

觀察者接口實(shí)現(xiàn)類

public interface DisplayElement {
    public void display();
}

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    public CurrentConditionsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);//注冊(cè)觀察者
    }
    /更新數(shù)據(jù)
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    public void display() {
        System.out.println("Current conditions: " + temperature
            + "F degrees and " + humidity + "% humidity");
    }
}

控制臺(tái)打印一下

public class WeatherStation {

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay =
            new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夫嗓,隨后出現(xiàn)的幾起案子迟螺,更是在濱河造成了極大的恐慌冲秽,老刑警劉巖舍咖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異锉桑,居然都是意外死亡排霉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門民轴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攻柠,“玉大人,你說我怎么就攤上這事后裸」迮ィ” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵微驶,是天一觀的道長(zhǎng)浪谴。 經(jīng)常有香客問我,道長(zhǎng)因苹,這世上最難降的妖魔是什么苟耻? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮扶檐,結(jié)果婚禮上凶杖,老公的妹妹穿的比我還像新娘。我一直安慰自己款筑,他們只是感情好智蝠,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奈梳,像睡著了一般杈湾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颈嚼,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天毛秘,我揣著相機(jī)與錄音,去河邊找鬼。 笑死叫挟,一個(gè)胖子當(dāng)著我的面吹牛艰匙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抹恳,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼员凝,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了奋献?” 一聲冷哼從身側(cè)響起健霹,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瓶蚂,沒想到半個(gè)月后糖埋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窃这,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年瞳别,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杭攻。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祟敛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兆解,到底是詐尸還是另有隱情馆铁,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布锅睛,位于F島的核電站埠巨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏衣撬。R本人自食惡果不足惜乖订,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望具练。 院中可真熱鬧乍构,春花似錦、人聲如沸扛点。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陵究。三九已至眠饮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铜邮,已是汗流浹背仪召。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工寨蹋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扔茅。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓已旧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親召娜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子运褪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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