《設計模式》- 觀察者模式

定義

定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則因此依賴於它的對象都會獲得通知並被自動更新java

使用場景

  • 關聯行爲場景,須要注意的是,關聯行爲是可拆分的,而不是「組合」關係。
  • 時間多級觸發場景
  • 跨系統的消息交換場景,如消息隊列、時間總線的處理機制。

UML 類圖

classDiagram
Subject o.. Observer
Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserver
class Subject{
    <<abstract>>
    +register(Observer)
    +unregister(Observer)
    +nofityObservers(Object)
}
class ConcreteSubject{
    +nofityObservers(Object)
}
class Observer{
    <<interface>>
    +update(Object)
}
class ConcreteObserver{
    +update(Object)
}
  • Subject: 抽象主題,也就是被觀察者(Observable)角色,抽象主題把因此觀察者對象的引用保存在一個集合裏,每一個主題均可以有任意數量的觀察者,抽象主題提供一個接口,能夠新增和刪除觀察者對象。
  • ConcerteSubject: 具體主題,該角色將有關狀態存入具體觀察者對象,在具體主題的內容狀態發生改變時,給全部註冊過的觀察者發出通知,具體主題角色又叫作具體觀察者(ConsreteObservable)角色。
  • Observer: 抽象觀察者,改角色是觀察者的抽象類,它定義了一個更新接口,使得在獲得主題的更改通知時更新本身。
  • ConcreteObserver: 具體觀察者,該角色實現抽象觀察者所定義的更新接口,以便在主題狀態發生改變時更新自身的狀態。

Android 中的觀察者模式

Android源碼中有不少使用了觀察者模式,好比OnClickListener、ContentObserver、 android.database.Observer 等。還有不少組件庫Rxjava、RxAndroid、EventBus;這裏咱們來看下經常使用的Adapter的notifyDataSetChanged()。android

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();
    }
    
}

複製代碼

這裏能夠看到BaseAdapter 裏有一個DataSetObservable 的被觀察者,經過register*()、unregister*()方法添加和刪除觀察者。咱們往下看DataSetObservable 這個類markdown

public class DataSetObservable extends Observable<DataSetObserver> {
    /** * 當數據變化時調用每一個觀察者的onChanged() 方法通知它們 */
    public void notifyChanged() {
        synchronized(mObservers) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
}

複製代碼

這裏其實很簡單,就是遍歷全部觀察者並調用它們的onChanged()。接下來咱們看是誰調用了BaseAdapter 的 registerDataSetObserver(DataSetObserver observer)方法。app

public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
        
        //省略代碼...

        // AbsListView#setAdapter will update choice mode states.
        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();
    }
複製代碼

以上能夠看出ListVeiw 中有一個觀察者(AdapterDataSetObserver)在setAdapter() 的時候註冊到了Adapter 的DataSetObservable 中,當Adapter 調用 notifyDataSetChanged() 方法時就會通知 ListView 中的觀察者(AdapterDataSetObserver)更新狀態。異步

小結

觀察者模式主要的做用就是解耦,將觀察者與被觀察者徹底隔離,只依賴於 Observer 和 Observable 抽象,提供代碼的靈活性和可擴展性。spa

優勢: 觀察者和被觀察者直接是抽象耦合,應對業務變化。加強系統靈活性、可擴展性。code

缺點: 在應用觀察者模式時須要考慮一下開發效率和運行效率問題,由於一個被觀察者可能直接或間接有不少觀察者,Java 消息中的通知默認順序執行,通知到因此觀察者可能須要花費些時間,若是一個觀察者卡頓,會影響總體的執行效率,這裏通常考慮採用異步的方式。orm

相關文章
相關標籤/搜索