觀察者模式
本篇文章大部分摘錄自 http://c.biancheng.net/view/1390.html
在現實世界中,許多物件并不是獨立存在的,其中一個物件的行為發生改變可能會導致一個或者多個其他物件的行為也發生改變,例如,某種商品的物價上漲時會導致部分商家高興,而消費者傷心;還有,當我們開車到交叉路口時,遇到紅燈會停,遇到綠燈會行,這樣的例子還有很多,例如,股票價格與股民、微信公眾號與微信用戶、氣象局的天氣預報與聽眾、小偷與警察等,
在軟體世界也是這樣,例如,Excel 中的資料與折線圖、餅狀圖、柱狀圖之間的關系;MVC 模式中的模型與視圖的關系;事件模型中的事件源與事件處理者,所有這些,如果用觀察者模式來實作就非常方便,
模式的定義與特點
觀察者(Observer)模式的定義:指多個物件間存在一對多的依賴關系,當一個物件的狀態發生改變時,所有依賴于它的物件都得到通知并被自動更新,這種模式有時又稱作發布-訂閱模式、模型-視圖模式,它是物件行為型模式,
觀察者模式是一種物件行為型模式,其主要優點如下,
- 降低了目標與觀察者之間的耦合關系,兩者之間是抽象耦合關系,
- 目標與觀察者之間建立了一套觸發機制,
它的主要缺點如下,
- 目標與觀察者之間的依賴關系并沒有完全解除,而且有可能出現回圈參考,
- 當觀察者物件很多時,通知的發布會花費很多時間,影響程式的效率,
模式的結構與實作
實作觀察者模式時要注意具體目標物件和具體觀察者物件之間不能直接呼叫,否則將使兩者之間緊密耦合起來,這違反了面向物件的設計原則,
1. 模式的結構
觀察者模式的主要角色如下,
- 抽象主題(Subject)角色:也叫抽象目標類,它提供了一個用于保存觀察者物件的聚集類和增加、洗掉觀察者物件的方法,以及通知所有觀察者的抽象方法,
- 具體主題(Concrete Subject)角色:也叫具體目標類,它實作抽象目標中的通知方法,當具體主題的內部狀態發生改變時,通知所有注冊過的觀察者物件,
- 抽象觀察者(Observer)角色:它是一個抽象類或介面,它包含了一個更新自己的抽象方法,當接到具體主題的更改通知時被呼叫,
- 具體觀察者(Concrete Observer)角色:實作抽象觀察者中定義的抽象方法,以便在得到目標的更改通知時更新自身的狀態,
觀察者模式的結構圖如圖 1 所示,

2. 實作例子
天氣作為該例子的主題,氣象局、媽媽還有學生都是天氣的觀察者,天氣發出提醒時,所有天氣觀察者都會做出回應,
// 抽象主題
public abstract class AbstractSubject {
protected List<Observer> observerList = new ArrayList<>();
public void add(Observer observer) {
observerList.add(observer);
}
public void remove(Observer observer) {
observerList.remove(observer);
}
public abstract void notifyObservers(String status);
}
// 抽象觀察者
public interface Observer {
void response(String status);
}
// 具體主題
public class WeatherSubject extends AbstractSubject {
@Override
public void notifyObservers(String status) {
for (Observer ob : observerList) {
ob.response(status);
}
}
}
// 具體觀察者 (氣象局、媽媽、學生)
public class WeatherCenterObserver implements Observer {
@Override
public void response(String status) {
if ("rain".equals(status))
System.out.println("氣象局:要下雨了!");
else
System.out.println("氣象局:天氣晴朗!");
}
}
// 媽媽
public class MomObserver implements Observer {
@Override
public void response(String status) {
if ("rain".equals(status))
System.out.println("媽媽:下雨了!回家收衣服!");
else
System.out.println("媽媽:好天氣,曬衣服!");
}
}
// 學生
public class StudentObserver implements Observer {
@Override
public void response(String status) {
if ("rain".equals(status))
System.out.println("學生黨:下雨了,出門帶傘!");
else
System.out.println("學生黨:天氣好!不用帶傘出門!");
}
}
測驗例子
public static void main(String[] args) {
AbstractSubject weatherSubject = new WeatherSubject();
weatherSubject.add(new WeatherCenterObserver());
weatherSubject.add(new MomObserver());
weatherSubject.add(new StudentObserver());
weatherSubject.notifyObservers("rain");
}
// 輸出結果:
// 氣象局:要下雨了!
// 媽媽:下雨了!回家收衣服!
// 學生黨:下雨了,出門帶傘!
我只做了一個簡單的例子便于理解觀察者模式,實際使用中,往往通過JMS和MQ來輔助實作觀察者模式,并且需要事件相關物件的傳導(使用泛型),這都是更高級的設計里需要考慮到的,
模式的應用場景
通過前面的分析與應用實體可知觀察者模式適合以下幾種情形,
- 物件間存在一對多關系,一個物件的狀態發生改變會影響其他物件,
- 當一個抽象模型有兩個方面,其中一個方面依賴于另一方面時,可將這二者封裝在獨立的物件中以使它們可以各自獨立地改變和復用,
模式的擴展
在 Java 中,通過 java.util.Observable 類和 java.util.Observer 介面定義了觀察者模式,只要實作它們的子類就可以撰寫觀察者模式實體,
1. Observable類
Observable 類是抽象目標類,它有一個 Vector 向量,用于保存所有要通知的觀察者物件,下面來介紹它最重要的 3 個方法,
- void addObserver(Observer o) 方法:用于將新的觀察者物件添加到向量中,
- void notifyObservers(Object arg) 方法:呼叫向量中的所有觀察者物件的 update,方法,通知它們資料發生改變,通常越晚加入向量的觀察者越先得到通知,
- void setChange() 方法:用來設定一個 boolean 型別的內部標志位,注明目標物件發生了變化,當它為真時,notifyObservers() 才會通知觀察者,
2. Observer 介面
Observer 介面是抽象觀察者,它監視目標物件的變化,當目標物件發生變化時,觀察者得到通知,并呼叫 void update(Observable o,Object arg) 方法,進行相應的作業,

3. 實作
http://c.biancheng.net/view/1390.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/50020.html
標籤:設計模式
上一篇:從回帖被刪,再說“簡單即是美”,對代碼完全掌控的重要性!
下一篇:MATPOWER的安裝詳細教程
