觀察者模式

觀察者模式(Observer Pattern)也叫作發佈-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式。這個模式的一個最重要的做用就是解耦。也就是將被觀察者和觀察者進行解耦,使得他們之間的依賴性更小,甚至作到毫無依賴。在觀察者模式中它定義了一種一對多的依賴關係,使得當每個對象改變狀態,則全部依賴於它的對象都會獲得通知並被自動更新。java

 

1. 觀察者模式結構

一個軟件系統經常要求在某一個對象的狀態發生變化的時候,某些其餘的對象作出相應的改變。作到這一點的設計方案有不少,可是爲了使系統可以易於複用,應該選擇低耦合度的設計方案。減小對象之間的耦合有利於系統的複用,可是同時設計師須要使這些低耦合度的對象之間可以維持行動的協調一致,保證高度的協做。觀察者模式是知足這一要求的各類設計方案中最重要的一種。下面以一個簡單的示意性實現爲例,討論觀察者模式的結構。測試

觀察者模式主要包含四種角色:this

  • Subject:抽象主題,也就是上面的被觀察者(Observable)角色。Subject把全部觀察者對象的引用保存在一個集合裏,而且可以動態的增長、取消觀察者spa

  • Observer:抽象觀察者,爲全部的具體觀察者定義一個接口,在獲得主題的通知時更新本身,這個接口叫作更新接口設計

  • ConcreteSubject:具體主題,也就是具體的被觀察者,將有關狀態存入具體觀察者對象;在具體主題的內部狀態改變時,給全部登記過的觀察者發出通知server

  • ConcreteObserver:具體觀察者,ConcreteObserver實現了抽象觀察者所定義的更新接口,再被觀察者通知改變是更新自身狀態,以便使自己的狀態與主題的狀態相協調對象

 

2. 簡單實現

  • 新建抽象主題接口

代碼塊rem

Javaget

public abstract class Subject {
//用來保存註冊的觀察者對象
private List<Observer> list = new ArrayList<Observer>();
//註冊觀察者對象:observer
public void attach(Observer observer) {
list.add(observer);
System.out.println("Attached an observer");
}
//刪除觀察者對象
public void detach(Observer observer) {
list.remove(observer);
}
//通知全部註冊的觀察者對象
public void nodifyObservers(String newState) {
for (Observer observer : list) {
observer.update(newState);
}
}
}

 

  • 新建具體主題

代碼塊

Java

public class ConcreteSubject extends Subject{
private String state;
public void change(String newState){
state = newState;
System.out.println("主題狀態爲:" + state);
// 狀態發生改變,通知各個觀察者
this.nodifyObservers(state);
}
}

 

 

  • 新建抽象觀察者

代碼塊

Java

public interface Observer {
// 更新狀態
public void update(String state);
}

 

  • 新建具體觀察者

代碼塊

Java

public class ConcreteObserver implements Observer {
//觀察者的狀態
private String observerState;
public void update(String state) {
/**
* 更新觀察者的狀態,使其與目標的狀態保持一致
*/
observerState = state;
System.out.println("狀態爲:" + observerState);
}
}

 

  • 測試類

代碼塊

Java

public class ObserverPatternTest {
public static void main(String[] args) {
// 建立主題對象
ConcreteSubject subject = new ConcreteSubject();
// 建立觀察者對象
Observer observer = new ConcreteObserver();
// 將觀察者對象登記到主題對象上
subject.attach(observer);
// 改變主題對象的狀態
subject.change("new state");
}
}

輸出結果:

 

3. Java對觀察者模式的支持

在java.util庫裏面,提供了一個Observable類和一個Observer接口。

  • Observable類

被觀察者類都是java.util.Observable類的子類。java.util.Observable提供公開的方法支持觀察者對象,這些方法中有兩個對Observable的子類很是重要:一個是setChanged(),另外一個是notifyObservers()。第一方法setChanged()被調用以後會設置一個內部標記變量,表明被觀察者對象的狀態發生了變化。第二個是notifyObservers(),這個方法被調用時,會調用全部登記過的觀察者對象的update()方法,使這些觀察者對象能夠更新本身。

 

  • Observer接口

 

這個接口只定義了一個方法,即update()方法,當被觀察者對象的狀態發生變化時,被觀察者對象的notifyObservers()方法就會調用這一方法。

 

經過Java的內置類改寫上述demo:

  • 新建具體主題類

代碼塊

Java

public class ObserverPatternTest {
public static void main(String[] args) {
// 建立主題對象
ConcreteSubject subject = new ConcreteSubject();
// 建立觀察者對象
ConcreteObserver observer = new ConcreteObserver();
// 將觀察者對象登記到主題對象上
subject.addObserver(observer);
// 改變主題對象的狀態
subject.change("new state");
}
}
  • 新建具體觀察者

代碼塊

Java

public class ConcreteSubject extends Observable {
private String state;
public String getState() {
return state;
}
public void change(String newState) {
setChanged();
state = newState;
System.out.println("主題狀態爲:" + state);
// 狀態發生改變,通知各個觀察者
notifyObservers();
}
}

從新運行測試類,可發現結果一致。

 

4. 優缺點

優勢:

  • 觀察者模式能夠實現表示層和數據邏輯層的分離,定義了穩定的消息更新傳遞機制,並抽象了更新接口,使得能夠有各類各樣不一樣的表示層充當具體觀察者角色。

  • 觀察者模式在觀察目標和觀察者之間創建一個抽象的耦合。觀察目標只須要維持一個抽象觀察者的集合,無須瞭解其具體觀察者。因爲觀察目標和觀察者沒有緊密地耦合在一塊兒,所以它們能夠屬於不一樣的抽象化層次。

  • 觀察者模式支持廣播通訊,觀察目標會向全部已註冊的觀察者對象發送通知,簡化了一對多系統設計的難度。

  • 觀察者模式知足「開閉原則」的要求,增長新的具體觀察者無須修改原有系統代碼,在具體觀察者與觀察目標之間不存在關聯關係的狀況下,增長新的觀察目標也很方便。

 

缺點:

  • 若是一個被觀察者對象有不少的直接和間接的觀察者的話,將全部的觀察者都通知到會花費不少時間

  • 若是在被觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,致使系統崩潰

  • 雖然觀察者模式能夠隨時使觀察者知道所觀察的對象發生了變化,可是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎麼發生變化的

相關文章
相關標籤/搜索