標籤:構建 -- 優缺點 imp 關係 並且 非同步作業 軟體測試 擴充性
觀察者模式是一種使用頻率非常高的模式,有時也被稱作發布/訂閱模式,屬於行為型模式,它最常用的是 GUI 系統、訂閱——發布系統,它一個重要作用就是解耦,使得它們之間的依賴性更小。觀察者模式定義了對象間一種一對多的依賴關係,使得每當一個對象改變狀態時,則所有依賴於它的對象都會得到通知並被自動更新。
1.觀察者模式的使用情景
關聯線為情境;事件多級觸發情境;跨系統的訊息交換情境(如訊息佇列、事件匯流排的處理機制)。
2.程式中使用觀察者模式的優缺點
| - |
觀察者模式 |
| 優點 |
觀察者和被觀察者之間是耦合抽象,應對業務變化;增強了系統靈活性、可擴充性。 |
| 缺點 |
開發調試變的比較複雜,Java中訊息的通知是順序執行,一個訊息的卡頓會影響整體的執行效率,所以使用觀察者模式還需要結合非同步作業的方式。 |
3.觀察者模式的UML類圖
Subject:抽象主題,被觀察(Observable)的角色;ConcreteSubject:具體主題;Observer:抽象觀察者;ConcreteObserver:具體的觀察者。
4.觀察者模式的實現
觀察者 Observer 和被觀察者 Observable 是 JDK 中的內建類型。
1.建立觀察者:
public class MyObserver implements Observer { private String name; public MyObserver(String name) { this.name = name; } @Override public void update(Observable o, Object arg) { System.out.println(name + ", update:" + arg); }}
3.編寫測試方法:
@Testpublic void test() throws Exception { // 被觀察者 MyObservable observable = new MyObservable(); // 觀察者 MyObserver observer1 = new MyObserver("test1"); MyObserver observer2 = new MyObserver("test2"); MyObserver observer3 = new MyObserver("test3"); MyObserver observer4 = new MyObserver("test4"); // 將觀察者註冊到被觀察者對象的觀察者列表中 observable.addObserver(observer1); observable.addObserver(observer2); observable.addObserver(observer3); observable.addObserver(observer4); // 發布訊息 observable.postNewPublication("new");}
輸出結果:
test4, update:newtest3, update:newtest2, update:newtest1, update:new
可以看到所有訂閱了被觀察者的觀察者都接收到了更新訊息,一對多的訂閱——發布系統就完成了。
5.Android系統原始碼中的應用情景1.notifyDataSetChanged() 方法
我們在使用 ListView 添加資料後,都會調用 Adapter 的 notifyDataSetChanged() 方法來動態更新資料。
notifyDataSetChanged() 方法被定義在 BaseAdapter 中,BaseAdapter 就是一個觀察者模式:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { // 資料集觀察者 private final DataSetObservable mDataSetObservable = new DataSetObservable(); public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } // 當資料集變化時,通知所有觀察者 public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } // 代碼省略}
我們跟進查看 mDataSetObservable.notifyChanged() 方法:
public class DataSetObservable extends Observable<DataSetObserver> { // 調用每個觀察者的 onChanged() 方法來通知它們被觀察者發生了變化 public void notifyChanged() { synchronized(mObservers) { // 調用所有觀察者的 onChanged() 方法 for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } // 代碼省略}
這段代碼就是在 mDataSetObservable.notifyChanged() 中遍曆所有觀察者,並且調用它們的 onChanged() 方法,從而告知觀察者發生了變化。
那麼這些觀察者是哪裡來的呢?其實是 ListView 通過 setAdapter() 方法設定 Adapter 產生的,我們來看看相關代碼:
public class ListView extends AbsListView { // 代碼省略 @Override public void setAdapter(ListAdapter adapter) { // 如果已經有了一個 Adapter,那麼先登出該 Adapter 對應的觀察者 if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } // 代碼省略 super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; // 擷取資料的數量 mItemCount = mAdapter.getCount(); checkFocus(); // 這裡注意:建立一個一個資料集觀察者 mDataSetObserver = new AdapterDataSetObserver(); // 將這個觀察者註冊到 Adapter 中,實際上是註冊到 DataSetObservable 中 mAdapter.registerDataSetObserver(mDataSetObserver); // 代碼省略 } else { // 代碼省略 } requestLayout(); } // 代碼省略}
我們可以看到,在設定 Adapter 時會構建一個 AdapterDataSetObserver,也就是觀察者,最後,將這個觀察者註冊到 Adapter 中。
到這裡,我們就知道了,當 ListView 的資料發生變化時,調用 Adapter 的 notifyDataSetChanged() 方法,這個方法又調用 DataSetObservable 的 notifyChanged() 方法,這個方法又調用所有觀察者(AdapterDataSetObserver)的 onChanged() 方法,在 onChanged() 方法中又會調用 ListView 重新布局的方法使得 ListView 重新整理介面,這就是一個觀察者模式。
Android 設計模式情景分析——觀察者模式