觀察者模式

1.觀察者模式概念

當(dāng)一個(gè)對(duì)象存在一對(duì)多的關(guān)系的時(shí)候画髓,則可以使用觀察者模式(Observer Pattern)独令。比如来庭,當(dāng)一個(gè)對(duì)象發(fā)生改變的時(shí)候宣决,所以依賴這個(gè)對(duì)象的對(duì)象都會(huì)接收到通知。觀察者模式屬于行為型模式吆你。

2.觀察者模式作用

定義對(duì)象間的一種一對(duì)多的依賴關(guān)系弦叶,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新妇多。

3.何時(shí)使用

一個(gè)對(duì)象(目標(biāo)對(duì)象)的狀態(tài)發(fā)生改變伤哺,所有的依賴對(duì)象(觀察者對(duì)象)都將得到通知,進(jìn)行廣播通知。

4.優(yōu)點(diǎn)和缺點(diǎn)

優(yōu)點(diǎn)
1)觀察者和被觀察者是抽象耦合的立莉。
2)建立一套觸發(fā)機(jī)制绢彤。
缺點(diǎn)
3)如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間蜓耻。
4)如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話茫舶,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰刹淌。
5)觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的饶氏,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。

5.例子解析

觀察者模式類圖

抽象觀察者:

public interface Observer {
    public void update(Object object);
}

具體觀察者:
具體觀察者一:

public class OberverOne implements Observer{

    @Override
    public void update(Object object) {
        Weather weather = (Weather) object;
        System.out.println("OberverOne檢測(cè)到氣候改變================");
        System.out.println("OberverOne--溫度:"+weather.getTemperatrue());
        System.out.println("OberverOne--氣壓:"+weather.getPressure());
        System.out.println("OberverOne--濕度:"+weather.getHumidity());
    }

}

具體觀察者二:

public class OberverTwo implements Observer{

    @Override
    public void update(Object object) {
        Weather weather = (Weather) object;
        System.out.println("OberverTwo檢測(cè)到氣候改變================");
        System.out.println("OberverTwo--溫度:"+weather.getTemperatrue());
        System.out.println("OberverTwo--氣壓:"+weather.getPressure());
        System.out.println("OberverTwo--濕度:"+weather.getHumidity());
    }
}

被觀察者(主題)
可以看到有勾,這里并沒(méi)有按照類圖將被觀察者設(shè)計(jì)為一個(gè)接口嚷往,Java JDK也提供觀察者模式接口,java.util.Observable就是被觀察者柠衅,這個(gè)類也沒(méi)有被設(shè)計(jì)為一個(gè)接口皮仁,而是一個(gè)類。雖然在設(shè)計(jì)模式中菲宴,為了實(shí)現(xiàn)程序可拓展贷祈,易維護(hù),通常建議多用組合喝峦,少用繼承势誊,但這只是一個(gè)理論,要根據(jù)具體情況使用設(shè)計(jì)模式谣蠢,只要滿足需求粟耻,我們又何必多做功夫。而且《Head First Design Patterns》中也說(shuō)到了眉踱,書(shū)中提到的設(shè)計(jì)模式挤忙,多多少少會(huì)有違背設(shè)計(jì)模式原則的地方。

public class Observed {

    private ArrayList<Observer> observers = new ArrayList<Observer>();

    public boolean attach(Observer observer) {
        return observers.add(observer);
    }
    
    public boolean remove(Observer observer)
    {
        return observers.remove(observer);
    }

    public void notifyAllObservers(Object object) {
        for (Observer observer : observers) {
            observer.update(object);
        }
    }
}

繼承了被觀察者的具體類

public class WeatherData extends Observed {

    private Weather weather;

    public WeatherData() {
        weather = new Weather();
    }

    public void measureNotifyChanged() {
        notifyAllObservers(weather);
    }

    public void setMeasureElement(float temperatrue, float humidity,
            float pressure) {
        this.weather.setTemperatrue(temperatrue);
        this.weather.setHumidity(humidity);
        this.weather.setPressure(pressure);
        measureNotifyChanged();
    }
}

數(shù)據(jù)實(shí)體

public class Weather {
    private float temperatrue;
    private float humidity;
    private float pressure;
    public float getTemperatrue() {
        return temperatrue;
    }
    public void setTemperatrue(float temperatrue) {
        this.temperatrue = temperatrue;
    }
    public float getHumidity() {
        return humidity;
    }
    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }
    public float getPressure() {
        return pressure;
    }
    public void setPressure(float pressure) {
        this.pressure = pressure;
    }
}

客戶端

public class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        OberverOne oberverOne = new OberverOne();
        OberverTwo oberverTwo = new OberverTwo();
        weatherData.attach(oberverOne);
        weatherData.attach(oberverTwo);
        while (true) {
            System.out.println("請(qǐng)選擇模式 1.設(shè)置監(jiān)聽(tīng) 2.改變數(shù)據(jù)");
            Scanner scanner = new Scanner(System.in);
            String temp = scanner.next();
            if (temp.equals("1")) {
                int temp2 = scanner.nextInt();
                if (temp2 == 1) {
                    if (weatherData.attach(oberverOne)) {
                        System.out.println("OberverOne監(jiān)聽(tīng)成功谈喳!");
                    }else
                        System.out.println("OberverOne監(jiān)聽(tīng)失敳崃摇!");
                }else if (temp2 == -1) {
            
                    if (weatherData.remove(oberverOne)) {
                        System.out.println("OberverOne取消監(jiān)聽(tīng)成功婿禽!");
                    }else
                        System.out.println("OberverOne取消監(jiān)聽(tīng)失斏蜕!");
                }else if (temp2 == 2) {
                    if (weatherData.attach(oberverOne)) {
                        System.out.println("OberverTwo監(jiān)聽(tīng)成功扭倾!");
                    }else
                        System.out.println("OberverTwo監(jiān)聽(tīng)失數砹恪!");
                }else if (temp2 == -2) {
                    if (weatherData.remove(oberverOne)) {
                        System.out.println("OberverTwo取消監(jiān)聽(tīng)成功膛壹!");
                    }else
                        System.out.println("OberverTwo取消監(jiān)聽(tīng)失敿葜小琼牧!");
                }
            }else if (temp.equals("2")) {
                System.out.println("請(qǐng)輸入溫度,氣壓哀卫,濕度:");
                
                float temperatrue = scanner.nextFloat();
                float humidity = scanner.nextFloat();
                float pressure = scanner.nextFloat();
                weatherData.setMeasureElement(temperatrue, pressure, humidity);
            }
        }

    }
}

6.調(diào)用JDK內(nèi)部觀察者例子

觀察者就沒(méi)什么好說(shuō)的了,直接實(shí)現(xiàn)java.util.Obserser接口,重寫(xiě)update()方法即可:

public class CurrentConditionDisplay implements Observer {

    private Weather weather;
    public CurrentConditionDisplay() {
    }
    public void display(Weather weather) {
        System.out.println("Current condition: "+weather.getTemperatrue()+"F degree and humidity: "+weather.getHumidity()+"% humidity");
    }
    public void update(Observable o, Object arg) {
        weather = (Weather) arg;
        this.display(weather);
        
    }
}

被觀察者除了繼承java.util.Observable撬槽,還需要做兩個(gè)步驟:
1)先調(diào)用setChange(),標(biāo)記狀態(tài)已改變的事實(shí)此改。
2)然后調(diào)用兩個(gè)notifyObserver中的一個(gè):

public class WeatherData extends Observable {

    private Weather weather;
    public WeatherData() {
        weather = new Weather();
    }
@Override
public void notifyObservers(Object arg) {
    // TODO Auto-generated method stub
    super.notifyObservers(weather);
}

    public void measureNotifyChanged()
    {   
        this.setChanged();
        notifyObservers();
    }
    
    public void setMeasureElement(float temperatrue,float humidity,float pressure)
    {
        this.weather.setTemperatrue(temperatrue);
        this.weather.setHumidity(humidity);
        this.weather.setPressure(pressure);
        measureNotifyChanged();
    }
}

詳細(xì)代碼可以通過(guò)文章結(jié)尾提供的地址下載源碼,查看項(xiàng)目下的com.lgy.test.four包的內(nèi)容侄柔。
notifyObserver()或notifyObserver(Object object)

7.總結(jié)

設(shè)計(jì)模式六大原則:
1共啃、開(kāi)閉原則(Open Close Principle)
開(kāi)閉原則的意思是:對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉暂题。在程序需要進(jìn)行拓展的時(shí)候移剪,不能去修改原有的代碼,實(shí)現(xiàn)一個(gè)熱插拔的效果薪者。簡(jiǎn)言之纵苛,是為了使程序的擴(kuò)展性好,易于維護(hù)和升級(jí)言津。想要達(dá)到這樣的效果攻人,我們需要使用接口和抽象類,后面的具體設(shè)計(jì)中我們會(huì)提到這點(diǎn)悬槽。
2怀吻、里氏代換原則(Liskov Substitution Principle)
里氏代換原則是面向?qū)ο笤O(shè)計(jì)的基本原則之一。 里氏代換原則中說(shuō)初婆,任何基類可以出現(xiàn)的地方蓬坡,子類一定可以出現(xiàn)。LSP 是繼承復(fù)用的基石磅叛,只有當(dāng)派生類可以替換掉基類屑咳,且軟件單位的功能不受到影響時(shí),基類才能真正被復(fù)用弊琴,而派生類也能夠在基類的基礎(chǔ)上增加新的行為乔宿。里氏代換原則是對(duì)開(kāi)閉原則的補(bǔ)充。實(shí)現(xiàn)開(kāi)閉原則的關(guān)鍵步驟就是抽象化访雪,而基類與子類的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn)详瑞,所以里氏代換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范。
3臣缀、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)
這個(gè)原則是開(kāi)閉原則的基礎(chǔ)坝橡,具體內(nèi)容:針對(duì)接口編程,依賴于抽象而不依賴于具體精置。
4计寇、接口隔離原則(Interface Segregation Principle)
這個(gè)原則的意思是:使用多個(gè)隔離的接口,比使用單個(gè)接口要好。它還有另外一個(gè)意思是:降低類之間的耦合度番宁。由此可見(jiàn)元莫,其實(shí)設(shè)計(jì)模式就是從大型軟件架構(gòu)出發(fā)、便于升級(jí)和維護(hù)的軟件設(shè)計(jì)思想蝶押,它強(qiáng)調(diào)降低依賴踱蠢,降低耦合。
5棋电、迪米特法則茎截,又稱最少知道原則(Demeter Principle)
最少知道原則是指:一個(gè)實(shí)體應(yīng)當(dāng)盡量少地與其他實(shí)體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對(duì)獨(dú)立赶盔。
6企锌、合成復(fù)用原則(Composite Reuse Principle)
合成復(fù)用原則是指:盡量使用合成/聚合的方式,而不是使用繼承于未。
原則畢竟是理論撕攒,很多時(shí)候要根據(jù)具體情況來(lái)使用這些原則,不要生搬硬套烘浦,強(qiáng)迫一定要符合這個(gè)原則打却,不要忘了最初的目的,我們只是為了讓程序更好維護(hù)罷了谎倔。

8.源碼下載

http://download.csdn.net/detail/lgywsdy/9748282

9.參考文章

http://www.runoob.com/design-pattern/observer-pattern.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柳击,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子片习,更是在濱河造成了極大的恐慌捌肴,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藕咏,死亡現(xiàn)場(chǎng)離奇詭異状知,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)孽查,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門饥悴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人盲再,你說(shuō)我怎么就攤上這事西设。” “怎么了答朋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵贷揽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我梦碗,道長(zhǎng)禽绪,這世上最難降的妖魔是什么蓖救? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮印屁,結(jié)果婚禮上循捺,老公的妹妹穿的比我還像新娘。我一直安慰自己雄人,他們只是感情好从橘,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著柠衍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪晶乔。 梳的紋絲不亂的頭發(fā)上珍坊,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音正罢,去河邊找鬼阵漏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛翻具,可吹牛的內(nèi)容都是我干的履怯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼裆泳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叹洲!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起工禾,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤运提,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后闻葵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體民泵,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年槽畔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了栈妆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厢钧,死狀恐怖鳞尔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情早直,我是刑警寧澤铅檩,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站莽鸿,受9級(jí)特大地震影響昧旨,放射性物質(zhì)發(fā)生泄漏拾给。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一兔沃、第九天 我趴在偏房一處隱蔽的房頂上張望蒋得。 院中可真熱鬧,春花似錦乒疏、人聲如沸额衙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)窍侧。三九已至,卻和暖如春转绷,著一層夾襖步出監(jiān)牢的瞬間伟件,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工议经, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斧账,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓煞肾,卻偏偏與公主長(zhǎng)得像咧织,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子籍救,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

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

  • 1 場(chǎng)景問(wèn)題# 1.1 訂閱報(bào)紙的過(guò)程## 來(lái)考慮實(shí)際生活中訂閱報(bào)紙的過(guò)程习绢,這里簡(jiǎn)單總結(jié)了一下,訂閱報(bào)紙的基本流程...
    七寸知架構(gòu)閱讀 4,631評(píng)論 5 57
  • 本文的結(jié)構(gòu)如下: 什么是觀察者模式 為什么要用該模式 模式的結(jié)構(gòu) 代碼示例 推模型和拉模型 優(yōu)點(diǎn)和缺點(diǎn) 適用環(huán)境 ...
    w1992wishes閱讀 1,441評(píng)論 0 16
  • 觀察者模式Observer 背景 1.概述 一些面向?qū)ο蟮木幊谭绞津迹峁┝艘环N構(gòu)建對(duì)象間復(fù)雜網(wǎng)絡(luò)互連的能力毯炮。當(dāng)對(duì)象...
    踐行者閱讀 1,568評(píng)論 0 4
  • 設(shè)計(jì)模式之六大原則(轉(zhuǎn)載) 關(guān)于設(shè)計(jì)模式的六大設(shè)計(jì)原則的資料網(wǎng)上很多...
    霄霄霄霄閱讀 900評(píng)論 0 1
  • 觀察者模式中通常有兩個(gè)基本的概念主題:觀察者和被觀察者。當(dāng)被觀察者狀態(tài)發(fā)生改變時(shí)耸黑,需要通知相應(yīng)的觀察者桃煎,當(dāng)然,每個(gè)...
    時(shí)待吾閱讀 1,064評(píng)論 0 2