觀察者模式中通常有兩個基本的概念主題:觀察者和被觀察者。當被觀察者狀態發生改變時,需要通知相應的觀察者,當然,每個被觀察者所對應的觀察者可能不知一個,他們之間是1:n的關系。用專業一點的術語對觀察者模式的描述為:當一個對象變化時,其它依賴該對象的對象都會收到通知,并且隨著變化。
觀察者模式說明:
觀察者與被觀察者成員變量關系(即觀察者需要是被觀察者的某種成員變量)或被觀察者可以有指向觀察者的引用;當被觀察者某種方法執行或者狀態改變時,其內部實現中調用了觀察者的相關方法。
(一個是能夠找的到觀察者,為調用觀察者的函數提供指針引用;一個是 能夠執行相關觀察者對應的函數調用 具有權限和對應的參數條件)
觀察者模式的一般實現方式如下:
1.定義觀察者所具有的共同的接口:
1interfaceObserver {2publicvoidupdate();3}
2.定義兩個觀察者:
1classObserverAimplementsObserver {@Overridepublicvoidupdate() {System.out.println("ObserverA has received!");}}
1classObserverBimplementsObserver {23@Override4publicvoidupdate() {5System.out.println("ObserverB has received!");6}7}
3.定義被觀察者所具有的抽象父類:
1abstractclassObservable {23privateVector
vector =newVector();45publicvoidadd(Observer observer) {6vector.add(observer);7}89publicvoiddel(Observer observer) {10vector.remove(observer);11}1213publicvoidnotifyObservers() {14Enumeration enumo =vector.elements();15while(enumo.hasMoreElements()) {16enumo.nextElement().update();17}18}1920publicvoidoperation() {2122}23}
4.定義具體的被觀察者:
classConcretObservableextendsObservable{
@Overridepublicvoidoperation() {
System.out.println("update self!");
notifyObservers();
}
}
5.測試:
1publicclassObserverTest {23publicstaticvoidmain(String[] args) {4Observable sub =newConcretObservable();5sub.add(newObserverA());6sub.add(newObserverB());78sub.operation();9}1011}
初始化時,被觀察者 如果申明對象類型為observable(抽象類型) 則不能調用自己聲明實現的方法,只能調用父類(抽象類observable聲明的接口,不管有沒有實現(實現類中會實現抽象方法))
建立 觀察者與被觀察者的成員變量關系
被觀察者的某一動作觸發了 觀察者的改變 -- 即在被觀察者的方法實現中調用 觀察者的相關部分的方法操作,同時為了保障 被觀察者 可以同時被 多個觀察者監測, 觀察者與被觀察者本身應該存在一定的關聯關系,可能是成員變量關系,也可能是方法調用關系
抽象類 與接口的區別就是可以實現已聲明的方法,在子類繼承時,可重寫也可直接調用當前抽象類的 已實現方法。
抽象類里的函數只聲明不實現的話,需要添加關鍵字abstract,子類繼承抽象類時需要實現該抽象類。
在抽象類的notifybserves() 方法中 執行update操作時,每個對象元素都實現了observer接口,同時,父類引用指向子類對象,因此,執行的update方法不盡相同, 這就是運行時多態。
觀察者模式的應用場景:
1、? 對一個對象狀態的更新,需要其他對象同步更新,而且其他對象的數量動態可變。
2、? 對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節。
觀察者模式的優點:
1、? Subject和Observer之間是松偶合的,分別可以各自獨立改變。
2、? Subject在發送廣播通知的時候,無須指定具體的Observer,Observer可以自己決定是否要訂閱Subject的通知。
3、? 遵守大部分GRASP原則和常用設計原則,高內聚、低偶合。
觀察者模式的效果有以下的優點:第一、觀察者模式在被觀察者和觀察者之間建立一個抽象的耦合。觀察者模式有下面的缺點:第一、如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
觀察者模式的效果有以下的優點:
第一、觀察者模式在被觀察者和觀察者之間建立一個抽象的耦合。被觀察者角色所知道的只是一個具體觀察者列表,每一個具體觀察者都符合一個抽象觀察者的接口。被觀察者并不認識任何一個具體觀察者,它只知道它們都有一個共同的接口。
由于被觀察者和觀察者沒有緊密地耦合在一起,因此它們可以屬于不同的抽象化層次。如果被觀察者和觀察者都被扔到一起,那么這個對象必然跨越抽象化和具體化層次。
第二、觀察者模式支持廣播通訊。被觀察者會向所有的登記過的觀察者發出通知,
觀察者模式有下面的缺點:
第一、如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
第二、如果在被觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,導致系統崩潰。在使用觀察者模式是要特別注意這一點。
第三、如果對觀察者的通知是通過另外的線程進行異步投遞的話,系統必須保證投遞是以自恰的方式進行的。
第四、雖然觀察者模式可以隨時使觀察者知道所觀察的對象發生了變化,但是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎么發生變化的。
觀察者模式的應用場景:
1、 對一個對象狀態的更新,需要其他對象同步更新,而且其他對象的數量動態可變。
2、 對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節。
場景描述:
* 哈票以購票為核心業務(此模式不限于該業務),但圍繞購票會產生不同的其他邏輯,如:
* 1、購票后記錄文本日志
* 2、購票后記錄數據庫日志
* 3、購票后發送短信
* 4、購票送抵扣卷、兌換卷、積分
* 5、其他各類活動等
*
* 傳統解決方案:
* 在購票邏輯等類內部增加相關代碼,完成各種邏輯。
*
* 存在問題:
* 1、一旦某個業務邏輯發生改變,如購票業務中增加其他業務邏輯,需要修改購票核心文件、甚至購票流程。
* 2、日積月累后,文件冗長,導致后續維護困難。
*
* 存在問題原因主要是程序的"緊密耦合",使用觀察模式將目前的業務邏輯優化成"松耦合",達到易維護、易修改的目的,
* 同時也符合面向接口編程的思想。
*
* 觀察者模式典型實現方式:
* 1、定義2個接口:觀察者(通知)接口、被觀察者(主題)接口
* 2、定義2個類,觀察者對象實現觀察者接口、主題類實現被觀者接口
* 3、主題類注冊自己需要通知的觀察者
* 4、主題類某個業務邏輯發生時通知觀察者對象,每個觀察者執行自己的業務邏輯。