觀察者模式(常用設(shè)計模式)
觀察者模式谬俄,是類的行為模式蝇更,又叫做發(fā)布訂閱模式,模型視圖模式,源監(jiān)聽器模式翁都。
動機
將一個系統(tǒng)分割成一系列相互協(xié)作的類有一個很不好的副作用,那就是需要維護相關(guān)對象的一致性罐寨。
我們不希望為了維護一致性而使各類緊密耦合自沧,這樣會給維護、擴展和重用都帶來不便明刷。
而觀察者模式是主題(Subject)可以有任意數(shù)量依賴它的觀察者(Observer)婴栽,當(dāng)主題狀態(tài)發(fā)生改變時,
所有的觀察者都能收到通知辈末,而Subject并不需要知道具體的Observer是誰愚争,因為它只是依賴于Observer的抽象,
這正是依賴抽象不依賴具體的設(shè)計提現(xiàn)挤聘。
結(jié)構(gòu)圖如下:觀察者模式所涉及的角色有:
● 抽象主題(Subject)角色:抽象主題角色把所有對觀察者對象的引用保存在一個聚集(比如ArrayList對象)里轰枝,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口组去,可以增加和刪除觀察者對象鞍陨,抽象主題角色又叫做抽象被觀察者(Observable)角色。
● 具體主題(ConcreteSubject)角色:將有關(guān)狀態(tài)存入具體觀察者對象从隆;在具體主題的內(nèi)部狀態(tài)改變時诚撵,給所有登記過的觀察者發(fā)出通知缭裆。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。
● 抽象觀察者(Observer)角色:為所有的具體觀察者定義一個接口砾脑,在得到主題的通知時更新自己幼驶,這個接口叫做更新接口。
● 具體觀察者(ConcreteObserver)角色:存儲與主題的狀態(tài)自恰的狀態(tài)韧衣。具體觀察者角色實現(xiàn)抽象觀察者角色所要求的更新接口盅藻,以便使本身的狀態(tài)與主題的狀態(tài) 像協(xié)調(diào)。如果需要畅铭,具體觀察者角色可以保持一個指向具體主題對象的引用氏淑。
java提供的支持
在java語言中,提供了一個Observable類以及一個observer接口硕噩,構(gòu)成java語言對觀察者模式的支持假残。
observer接口
? Observer接口,是指觀察者類繼承的接口炉擅。指只定義了一個方法辉懒,即update()方法,當(dāng)被觀察者對象的狀態(tài)發(fā)生變化時谍失,被觀察者對象的notifyObserver()方法就會調(diào)用這一個方法眶俩。
Observable
? 該類是被觀察者類的超類,提供公開的方法支持被觀察者對象快鱼。列舉其中兩個方法比較重要:
- setChange() 被調(diào)用后颠印,會設(shè)置一個內(nèi)部標(biāo)記變量,代表被觀察者的狀態(tài)發(fā)生了變化抹竹。
- notifyObservers,這個方法被調(diào)用后线罕,會調(diào)用所有觀察者對象的update()方法。是這些觀察者對象可以更新自己窃判。
怎樣使用java提供的支持
看代碼
觀察者模式的優(yōu)缺點
優(yōu)點:
- 被觀察者與觀察者之間建立了抽象的松耦合钞楼。兩者之間的改變不會影響太多彼此。
- 觀察者模式支持廣播通信袄琳,被觀察者會向所有登記過的觀察者發(fā)出通知窿凤。
缺點:
如果一個被觀察者對象有很多直接或者間接的觀察者的話,將所有觀察者通知到會花很多時間跨蟹。
-
第二雳殊、如果在被觀察者之間有循環(huán)依賴的話,被觀察者會觸發(fā)它們之間進行循環(huán)調(diào)用窗轩,導(dǎo)致系統(tǒng)崩潰夯秃。在使用觀察者模式是要特別注意這一點。
第三、如果對觀察者的通知是通過另外的線程進行異步投遞的話仓洼,系統(tǒng)必須保證投遞是以自恰的方式進行的介陶。
第四、雖然觀察者模式可以隨時使觀察者知道所觀察的對象發(fā)生了變化色建,但是觀察者模式?jīng)]有相應(yīng)的機制使觀察者知道所觀察的對象是怎么發(fā)生變化的哺呜。
應(yīng)用場景
1、 對一個對象狀態(tài)的更新箕戳,需要其他對象同步更新某残,而且其他對象的數(shù)量動態(tài)可變。
2陵吸、 對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節(jié)玻墅。