很久之前,自己也曾看過一些設計模式的內容,最近在做一些程式程式碼設計的時,發現忘得差不多了,很多模式也只是有大致影響,決定重新將一些常用的模式複習一下。今天一個模式觀察者模式。
觀察者模式
觀察者模式屬於行為模式中的一種;觀察者模式定物件一個一對多的依賴關係,讓多個觀察者物件同時監聽同一個主題物件,主題物件在狀態發生改變時,通知所有觀察者物件使他們能夠更新自己。
上面是觀察者模式設計類圖-
subject:它是抽象主題的介面,物件通過此介面將自己註冊為觀察者,或將自己從觀察中者刪除
-
ConcreteSubject:一個實現主題介面的具體主題,除了實現註冊和刪除的方法外,它還有一個change方法,用來在狀態改變時通知所有觀察者
-
Observer:觀察者介面,所有具體的觀察者都實現此介面
-
ConcreteObserver:具體的觀察者
package com.mtx.demo.observer;
import java.util.ArrayList;
import java.util.List;
public abstract class Subject {
// 儲存註冊的觀察者物件
private List<Observer> list = new ArrayList<Observer>();
// 註冊觀察者物件
public void attach(Observer observer) {
list.add(observer);
System.out.println("新增新的觀察者");
}
// 刪除觀察者物件
public void detach(Observer observer) {
list.remove(observer);
System.out.println("刪除一個觀察者");
}
// 通知所有註冊的觀察者物件
public void nodifyObservers(String newState) {
for (Observer observer : list) {
observer.update(newState);
}
}
}
複製程式碼
一個具體主題
package com.mtx.demo.observer;
public class ConcreteSubject extends Subject {
private String state;
public String getState() {
return state;
}
// 狀態發生改變,通知各個觀察者
public void change(String newState) {
state = newState;
this.nodifyObservers(state);
}
}
複製程式碼
抽象的觀察者
package com.mtx.demo.observer;
public interface Observer {
// 更新介面
public void update(String state);
}
複製程式碼
一個具體觀察者
package com.mtx.demo.observer;
public class ConcreteObserver implements Observer {
private String observerState;
@Override
public void update(String state) {
observerState = state;
System.out.println("觀察者狀態跟新了:" + observerState);
}
}
複製程式碼
客戶端中,我們建立一個具體主題物件,在建立一個觀察者物件,之後將觀察註冊到主題物件像上,這樣當主題物件的狀態改變時,所有的觀察者物件都會收到通知,改變自己的狀態。
package com.mtx.demo.observer;
public class Client {
public static void main(String[] args) {
// 建立主題物件
ConcreteSubject subject = new ConcreteSubject();
// 建立觀察者物件
Observer observer = new ConcreteObserver();
// 將觀察者物件登記到主題物件上
subject.attach(observer);
// 改變主題物件的狀態
subject.change("有新的技術部落格了");
}
}
複製程式碼
執行程式碼結果如下
問題
- 觀察者模式中一對多是如何體現的
主題是一個具有狀態的物件,而多個觀察者可以使用這個主題的狀態,多個觀察者依賴主題物件來告訴他們這些狀態何時改變,這就產生了一個主題對應多觀察者的關係
- 觀察者模式是鬆如何做到耦合的
主題只知道觀察者實現了某一個介面(Observer介面),主題不用知道觀察者具體是誰,做了哪些操作等,任何時候我們都可以新增新的觀察者,那是因為主題唯一依賴的是一個觀察者的Observer介面的物件列表,因此我們可以隨時新增觀察者,有新的主題出現時主題程式碼不用修改。
推模型和拉模型。
- 推模型:主題物件向觀察者推送主題的詳細資訊,不管觀察者是否需要,推送的資訊通常是主題物件的全部或部分資料,剛才上面的例子就是一個推模型。
推模型會是觀察者難以複用,因為每個觀察者的updata方法的引數可能不同,資料量非常大的時候推模型不適合
- 拉模型:主題物件在通知觀察者的時候,只傳遞少量資訊。如果觀察者需要更具體的資訊,由觀察者主動到主題物件中獲取,相當於是觀察者從主題物件中拉資料。一般這種模型的實現中,會把主題物件自身通過update()方法傳遞給觀察者,這樣在觀察者需要獲取資料的時候,就可以通過這個引用來獲取了。
另外Java語言提供的對觀察者模式的支援,在java.util包中,提供了一個Observable類以及一個Observer介面
- 優點:
1.在觀察者和被觀察者之間建立一個抽象的耦合;
2.支援廣播通訊
- 缺點:
1.如果一個被觀察者物件有很多觀察者,將所有觀察者通知到會花費很多時間;
2.如果在被觀察者之間有迴圈依賴,被觀察者會觸發他們之間的迴圈呼叫,導致系統崩潰;
3.觀察者沒有相應的方式使其知道所觀察的物件時怎麼發生變化的。
參考:Head First 設計模式