設計模式--觀察者模式

一、問題的提出
舉例:
WeatherData是氣象站獲取數(shù)據(jù)的對象,通過他獲取到數(shù)據(jù)后更新到不同的布告板上。
WeatherData有三個方法:getTemperature(), getHumidity(), getPressure()用于獲取溫度,濕度,氣壓值
當新數(shù)據(jù)獲得后,可以調(diào)用WeatherData中的measurementsChanged()方法,更新到不同的布告板上。
錯誤的設計:


image.png

二、初步認識
首先看看報紙的訂閱是如何進行的:
1、報社的業(yè)務是出版報紙
2、向某家報社訂閱報紙,只要他們有新報紙出版,就給你送來,只要你是他們的訂戶,就會一直收到新報紙
3、當你不想再看報紙時,取消訂閱,他們就不會再送新報紙了
4、只要報社還在運營,就會一直有人向他們訂閱報紙或取消訂閱
出版者(被觀察者Subject) + 訂閱者(觀察者Observe) = 觀察者模式


image.png

觀察者模式--在對象之間定義了一對多的依賴,這樣一來,當一個對象改變狀態(tài),依賴它的對象會收到通知并自動更新。
image.png

三、模式類圖
image.png

四、優(yōu)點
觀察者模式提供了一種對象設計,讓被觀察者和觀察者之間松耦合,他們可以交互,但是不需要知道彼此的細節(jié),被觀察者只需要知道觀察者實現(xiàn)了Oberver接口,并不需要知道觀察者的具體類是誰,做了什么細節(jié)操作。因為被觀察者唯一依賴的是一個實現(xiàn)Observer接口的對象列表,所以可以隨時增加觀察者,也可以用新的觀察者取代現(xiàn)有的觀察者,刪除觀察者。當有新的觀察者出現(xiàn)時,無需修改被觀察者代碼,被觀察者只把消息發(fā)送給觀察者,觀察者如何處理,被觀察者并不關(guān)心。
Tips:

松耦合的設計能讓我們建立有彈性的OO系統(tǒng),能應對變化,對象之間的相互依賴降到了最低。

五、解決最初氣象站的問題
1、首先建立被觀察者Subject接口,用于注冊、刪除、通知觀察者


image.png

2、在WeatherData中實現(xiàn)被觀察者Subject接口


image.png

3、建立布告板實現(xiàn)觀察者Observer接口(有多個布告板(觀察者),實現(xiàn)的方法類似)
image.png

六、觀察者模式在android中的應用
1、通常在ListView的內(nèi)容變化時,會調(diào)用notifyDataSetChanged()這個方法,然后ListView里面的數(shù)據(jù)就會進行更新。感覺像是觀察者模式,具體是不是再看看源碼。

package android.widget; 
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(); 
  } 
  ......
}

這是一個觀察者模式,里面提供了注冊和注銷觀察者以及通知觀察者的方法。
這些方法是通過DataSetObservable這個類調(diào)用的:

package android.database;public class DataSetObservable extends Observable<DataSetObserver> {   
    public void notifyChanged() {
        synchronized(mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
    ......
}

這個類繼承自Observable,Observable中有一個protected final ArrayList<T> mObservers = new ArrayList<T>();,用來保存注冊的觀察者。mDataSetObservable.registerObserver(observer)和mDataSetObservable.unregisterObserver(observer)分別就是增加和刪除。
在notifyChanged方法中,循環(huán)這個集合,調(diào)用每一個觀察者的onChanged()方法。
那么ListView和Adapter什么時候成了訂閱關(guān)系。
在ListView的setAdapter()中

public class ListView extends AbsListView {
    public void setAdapter(ListAdapter adapter) {
        //如果已經(jīng)有了一個adapter,注銷這個adapter之前的觀察者,
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
       ......
       if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            //將新的adapter賦給mAdapter
            mAdapter = adapter;
        }
        ......
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            //保存之前的數(shù)據(jù)個數(shù)
            mOldItemCount = mItemCount;
            //獲取新的個數(shù)
            mItemCount = mAdapter.getCount();
            checkFocus();
            //創(chuàng)建數(shù)據(jù)集觀察者
            mDataSetObserver = new AdapterDataSetObserver();
            //注冊觀察者
            mAdapter.registerDataSetObserver(mDataSetObserver);
            ...
            }
        } else {
            ...
        }

        requestLayout();
    }
}

AdapterDataSetObserver是ListView的父類AbsListView的內(nèi)部類

package android.widget;
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
        ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
        ViewTreeObserver.OnTouchModeChangeListener,
        RemoteViewsAdapter.RemoteAdapterConnectionCallback {
       class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
        ······
    }
}

AdapterDataSetObserver是AdapterView.AdapterDataSetObserver的子類,所以要看super.onChanged()

package android.widget;
public abstract class AdapterView<T extends Adapter> extends ViewGroup {
    class AdapterDataSetObserver extends DataSetObserver {
        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();

            // Detect the case where a cursor that was previously invalidated has
            // been repopulated with new data.
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            //重新布局
            requestLayout();
        }
        ......
    }
}

整理一下:當ListView數(shù)據(jù)變化時,調(diào)用Adapter的notifyDataSetChange方法,這個方法調(diào)用DataSetObservable的notifyChanged方法,這個方法又會調(diào)用所有觀察者的onChanged方法,onChanged再調(diào)用重新布局View的方法,完成刷新數(shù)據(jù)的功能。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容