【設計模式】(二十六)–行爲型模式–觀察者模式
觀察者模式定義
Define a one-to many dependency between objects so that when one object changes state, all ites dependents are notified and updated automatically.
意思是:定義對象間一種一對多的依賴關係,是的每當一個對象改變狀態,則所有依賴於它的對象都會得到通知並被自動更新。
觀察者模式一般有一個元素:
- Subject 抽象主題(被觀察者),可以增加和刪除觀察者對象,有時候可能會直接實現。
- Observer 抽象觀察者,定義了一個統一的接口,供具體觀察者實現,在得到主題的通知時,會發消息調用此方法,更新自己。
- Concrete Subject 具體主題,實現了主體接口的類,處理觀察者列表並更新他們的變化。
- Concrete Observer 具體觀察者,實現抽象觀察者,一遍自身的狀態與主題的狀態同步變化。
觀察者模式的優點
- 1、觀察者和被觀察者是抽象耦合的。 被觀察者持有一個觀察者集合,無需關心具體 觀察者如何實現,觀察者變化時,只要通知遍歷觀察者列表,調用通用觀察者方法即可。
- 2、建立一套觸發機制,主題會向所有登記過的觀察者發出通知。支持廣播通訊。
觀察者模式還有以下缺點:
- 1、如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間,且開發和調試都比較複雜,排查問題也很困難。
- 2、如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能導致系統崩潰。
- 3、觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
- 4、如果對觀察者的通知是異步線程進行投遞,系統必須要保證投遞的順序執行。
因爲觀察者模式缺點明顯,所以需要注意:
- 避免循環引用
- 如果是順序執行,因爲註冊早的觀察者執行時間過長,或者因爲異常原因,導致後面觀察者無法執行或者等待過久問題
- 異步處理問題。如果異步調用觀察者統一方法,需要考慮線程安全等問題。
觀察者模式的使用場景
- 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的對象中使它們可以各自獨立地改變和複用。
- 一個對象的改變將導致其他一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,可以降低對象之間的耦合度。
- 一個對象必須通知其他對象,而並不知道這些對象是誰。
- 需要在系統中創建一個觸發鏈,A對象的行爲將影響B對象,B對象的行爲將影響C對象……,可以使用觀察者模式創建一種鏈式觸發機制。
觀察者模式的簡單實現
類圖
實現
public class Test {
public static void main(String[] args) {
Subject subject = new Subject();
new DaShaoObserver(subject);
new ErShaoObserver(subject);
new SanShaoObserver(subject);
subject.publishNews("詹姆斯中國行活動於7月22日來上海!", "詹姆斯");
subject.publishNews("7月1日周杰倫上海無與倫比演唱會!", "周杰倫");
}
}
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();
private String headline = null;
public void publishNews(String news, String user) {
headline = news;
notifyAllObservers(news, user);
}
public void subscribe(Observer observer) {
observers.add(observer);
}
public void notifyAllObservers(String news, String user) {
for (Observer observer : observers) {
observer.notice(news, user);
}
}
}
public abstract class Observer {
protected Subject subject;
public abstract void notice(String news, String user);
}
public class DaShaoObserver extends Observer {
public DaShaoObserver(Subject subject) {
this.subject = subject;
this.subject.subscribe(this);
}
@Override
public void notice(String news, String user) {
if ("詹姆斯".equals(user)) {
System.out.println("大少收到新聞" + news + ",通知三少,要不要去!");
} else if ("周杰倫".equals(user)) {
System.out.println("大少收到新聞" + news + ",要買票去現場!");
} else {
System.out.println("大少收到新聞" + news + ",吃瓜!");
}
}
}
public class ErShaoObserver extends Observer {
public ErShaoObserver(Subject subject) {
this.subject = subject;
this.subject.subscribe(this);
}
@Override
public void notice(String news, String user) {
if ("周杰倫".equals(user)) {
System.out.println("二少收到新聞" + news + ",要買票去現場!");
} else {
System.out.println("二少收到新聞" + news + ",吃瓜!");
}
}
}
public class SanShaoObserver extends Observer {
public SanShaoObserver(Subject subject) {
this.subject = subject;
this.subject.subscribe(this);
}
@Override
public void notice(String news, String user) {
if ("詹姆斯".equals(user)) {
System.out.println("三少收到新聞" + news + ",要買票去現場!");
} else {
System.out.println("三少收到新聞" + news + ",吃瓜!");
}
}
}
結果