定義
觀察者模式(Observer Pattern):定義對象之間的一種一對多的依賴關係,使得每當一個對象狀態發生改變時其相關的依賴對象皆得到通知並且被自動更新。
結構
- Subject(目標):目標又稱爲主題,它是指被觀察的對象。在目標中定義了一個觀察者集合,一個觀察目標可以接受任意數量的觀察者來觀察,它提供一些列方法來增加或刪除觀察者對象,同時它定義了通知方法notify()。目標類可以是接口,也可以是抽象類或具體類。
- ConcreteSubject(具體目標):具體目標是目標類的子類,它通常包含有經常發生改變的數據,當它的狀態發生改變時將向它的各個觀察者發出通知;同時它還實現了在目標類中定義的抽象業務邏輯方法(如果有)。如果無須擴展目標類,則具體目標類可以省略。
- Observer(觀察者):觀察者化辦公對於觀察目標的改變做出反應,觀察者一般定義爲接口,該接口聲明瞭更新數據的方法update(),因此又稱爲抽象觀察者。
- ConcreteObserver(具體觀察者):在具體觀察者中維護一個指向具體目標對象的引用,它儲存具體觀察者的有關狀態,這些狀態需要和具體目標狀態保持一致;它實現了在抽象觀察者Observer中定義的update()方法。通常在實現時可以調用具體目標類的attach()方法將自己添加到目標類的集合中或通過detach()方法將自己同目標類的集合中刪除。
代碼
Subject
import java.util.ArrayList;
import java.util.List;
public abstract class Subject {
// 定義一個觀察者集合用於儲存所有的觀察者對象
protected List<Observer> observers = new ArrayList<>();
// 註冊方法,用於向觀察者集合中增加一個觀察者
public void attach(Observer observer) {
observers.add(observer);
}
// 註銷方法,用於從觀察者集合中刪除一個觀察者
public void detach(Observer observer) {
observers.remove(observer);
}
// 聲明抽象通知方法
public abstract void notifyObservers();
}
ConcreteSubject
public class ConcreteSubject extends Subject {
// 實現通知方法
@Override
public void notifyObservers() {
// 遍歷觀察者集合,調用每一個觀察者的響應方法
observers.forEach(Observer::update);
}
}
Observer
public interface Observer {
// 聲明響應方法
void update();
}
ConcreteObserver
public class ConcreteObserver implements Observer {
@Override
public void update() {
// 具體響應實現
System.out.println("ConcreteObserver");
}
}
Test
public class Test {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer observer = new ConcreteObserver();
subject.attach(observer);
subject.notifyObservers();
}
}
JDK對觀察者模式的支持
在JDK的java.util包中提供了Observable類以及Observer接口,他們構成了JDK對觀察者模式的支持。
- Observer接口
java.util.Observer接口中只聲明瞭一個方法
void update(Observable o, Object arg);
當觀察目標的狀態發生改變時該方法會被調用,在Observer的子類中將實現update()方法,即具體觀察者可以根據需要具有不同的更新行爲。
- Observable類
Observable定義了一個Vector來儲存觀察者對象。
方法名 | 描述 |
---|---|
Observable() | 構造方法,實例化Vector |
addObserver(Observer o) | 用於註冊新的觀察者對象 |
deleteObserver(Observer o) | 用於刪除觀察者 |
notifyObservers()和notifyObservers(Object arg) | 通知方法,用於在方法內部循環調用沒有個觀察者的update()方法。 |
deleteObservers() | 清空集合,即刪除所有的觀察者對象 |
setChanged() | 該方法被調用會設置一個boolean類型的內部標記變量changed的值爲true,表示觀察目標對象的狀態發生了改變 |
clearChanged() | 設置changed = false,表示對象狀態不再發生改變或者已經通知了所有的觀察者對象,調用了它們的update()方法 |
hasChanged() | 用於測試對象狀態是否改變 |
countObservers() | 返回觀察值數量 |
優/缺點與適用環境
- 優點
- 可以實現表示層和數據邏輯層的分離,定義了穩定的消息更新傳遞機制,並抽象了更新接口,使得可以有各種各樣不同的表示層充當具體觀察者角色。
- 在觀察目標和觀察者之間建立一個抽象的耦合。觀察目標只需要維持一個抽象觀察者的集合,無須瞭解其具體觀察者。由於觀察目標和觀察者沒有緊密地耦合在起,因此它們可以屬於不同的抽象化層次。
- 支持廣播通信,觀察目標會向所有已註冊的觀察者對象發送通知,簡化了一對多系統設計的難度。
- 符合開閉原則,增加新的具體觀察者無須修改原有系統代碼,在具體觀察者與觀察目標之間不存在關聯關係的情況下增加新的觀察目標也很方便。
- 缺點
- 如果一個觀察目標對象有很多直接和間接觀察者,將所有的觀察者都通知到會花費很多時間。
- 如果在觀察者和觀察目標之間存在循環依賴,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。
- 觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
- 適用環境
- 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面,將這兩個方面封裝在獨立的對象中使它們可以各自獨立地改變和複用。
- 一個對象的改變將導致一個或多個其他對象也發生改變,而且不知道具體有多少對象將發生概念,也不知道這些對象是誰。
- 需要在系統中創建一個觸發鏈,A對象的行爲將影響B對象,B對象的行爲將影響C對象…,可以使用觀察者模式創建一種鏈式觸發機制。