1. 程式人生 > >Android 設計模式情景分析——觀察者模式

Android 設計模式情景分析——觀察者模式

get ble not exception 知識庫 system observe 行為型模式 .get

觀察者模式是一種使用頻率非常高的模式,有時也被稱作發布/訂閱模式,屬於行為型模式,它最常用的是 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.編寫測試方法:

@Test
public 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:new
test3, update:new
test2, update:new
test1, 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 設計模式情景分析——觀察者模式