設(shè)計(jì)模式之觀察者模式

一、什么叫觀察者?

先理解一個(gè)簡(jiǎn)單的例子:很多購(gòu)房者都在關(guān)注房子的價(jià)格變化,每當(dāng)房子的價(jià)格變化時(shí),所有購(gòu)房者都可以觀察得到,實(shí)際上購(gòu)房者都屬于觀察者。

  • 觀察者模式的定義:定義對(duì)象間一種一對(duì)多的依賴(lài)關(guān)系,使得每當(dāng)一個(gè)對(duì)象發(fā)生改變,則所有依賴(lài)她的對(duì)象都會(huì)等到通知并被自動(dòng)更新。
  • 使用場(chǎng)景:1、 關(guān)聯(lián)行為場(chǎng)景;2、事件多級(jí)觸發(fā)場(chǎng)景;3、跨系統(tǒng)的消息交互場(chǎng)景,如消息隊(duì)列、事件總線的處理機(jī)制

二、觀察者模式實(shí)現(xiàn)

在Java.util包中提供了Observable和Observer接口,使用它們即可完成觀察者模式。
Observable:需要被觀察的類(lèi)必須繼承Observable類(lèi)。Observable類(lèi)的常用方法有:

  • 1、public void addObserver(Observer o) : 添加一個(gè)觀察者;
  • 2、public void deleteObserver(Observer o):刪除一個(gè)觀察者;
  • 3、public void setChanged() ; 被觀察者狀態(tài)發(fā)生改變;
  • 4、public void notifyObservers(Object args) ; 通知所有觀察者狀態(tài)改變;

Observer:每個(gè)觀察者都需要實(shí)現(xiàn)Observer接口,Observer接口定義如下:

public interface Observer {
     /**
     *當(dāng)被觀察者發(fā)生變化,并調(diào)用了notifyObserver方法,就調(diào)用該方法
     * @param o   被觀察者
     * @param args  修改的內(nèi)容
     */
    void update(Observable o, Object arg);
}

例:

package sl.com.designmodedemo.observer;
import java.util.Observable;
import java.util.Observer;
/**
 * 定義房子為被觀察者
 */
class House extends Observable{
    private float price ;   //定義房子價(jià)格
    public House(float price) {
        this.price = price;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
        setChanged();           //通知變化點(diǎn)
        notifyObservers(price);      //通知所有觀察者價(jià)格改變
    }
    @Override
    public String toString() {
        return "房子的價(jià)格是:" + this.price;
    }
}
/**
 * 房子價(jià)格變化觀察者
 */
class HousePriceObserver implements Observer{
    private String name ;       //觀察房子價(jià)格變化的人名
    public HousePriceObserver(String name) {
        this.name = name;
    }
    @Override
    public void update(Observable o, Object arg) {
            if (arg instanceof Float){              //判斷參數(shù)類(lèi)型
                System.out.println(this.name + " 觀察到的價(jià)格更改為:" + ((float)arg));
            }
    }
}

/**
 * 測(cè)試
 */
public class Test {
    public static void main(String args[]){
        House house = new House(1000000.0F);
        HousePriceObserver observer1 = new HousePriceObserver("觀察者A");
        HousePriceObserver observer2 = new HousePriceObserver("觀察者B");
        HousePriceObserver observer3 = new HousePriceObserver("觀察者C");
        //加入觀察者
        house.addObserver(observer1);
        house.addObserver(observer2);
        house.addObserver(observer3);
        //輸出房子價(jià)格
        System.out.println(house);
        //修改房子價(jià)格
        house.setPrice(2000000.0F);
        System.out.println(house);
    }
}

程序運(yùn)行結(jié)果為:

房子的價(jià)格是:1000000.0
觀察者C 觀察到的價(jià)格更改為:2000000.0
觀察者B 觀察到的價(jià)格更改為:2000000.0
觀察者A 觀察到的價(jià)格更改為:2000000.0
房子的價(jià)格是:2000000.0

從程序運(yùn)行結(jié)果可以發(fā)現(xiàn),多個(gè)觀察者都在觀察著價(jià)格的變化,當(dāng)被觀察者房子價(jià)格一變化,則所有觀察者都會(huì)知道;、

三、Android 源碼分析

ListView是Android中重要控件之一,而ListView有一個(gè)Adapter,通常我們?cè)诮oListView的數(shù)據(jù)進(jìn)行操作變化后,都會(huì)調(diào)用Adapter的notifyDataSetChanged()方法,這是為什么呢?下面我們從源碼解析:
第一步,跟進(jìn)notifyDataSetChanged()方法,這個(gè)方法定義在android.widget的BaseAdapter中,具體代碼如下:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    //數(shù)據(jù)集觀察者
    private final DataSetObservable mDataSetObservable = new DataSetObservable();
    
    //代碼省略

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }
    //當(dāng)數(shù)據(jù)集變化時(shí),通知所有觀察者
   public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }
}

從這里應(yīng)該看出來(lái)BaseAdapter就是一個(gè)觀察者模式,那么BaseAdapter是如何運(yùn)作的?這些觀察者又是什么?下面接著一步一步的分析。
現(xiàn)在先到mDataSetObservalbe.notifyChanged()的源碼看看:

public class DataSetObservable extends Observable<DataSetObserver> {
    /**
    * 調(diào)用每個(gè)觀察者的onChanged函數(shù)來(lái)通知他們被觀察者發(fā)生了變化
    */
   public void notifyChanged() {
        synchronized(mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
    //代碼省略
}

這個(gè)代碼很簡(jiǎn)單,就是在mDataSetObservable.notifyChanged()中遍歷所有的觀察者,并且調(diào)用他的onChanged()方法,從而告知觀察者發(fā)生了變化。
那么 這些觀察者從哪里來(lái)的呢?其實(shí)這些觀察者是就是ListView在setAdapter方法設(shè)置Adapter產(chǎn)生的,我們看相關(guān)代碼:

    @Override
    public void setAdapter(ListAdapter adapter) {
        //如果已經(jīng)有了一個(gè)Adapter,并且mDataSetObserver不為空
        if (mAdapter != null && mDataSetObserver != null) {
            //先注銷(xiāo)該Adapter的觀察者
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        //代碼省略
       
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            //獲取數(shù)據(jù)的數(shù)量
            mItemCount = mAdapter.getCount();
            checkFocus();
           //注意這里:創(chuàng)建了一個(gè)數(shù)據(jù)觀察者
            mDataSetObserver = new AdapterDataSetObserver();
            //將這個(gè)觀察者注冊(cè)到Adapter中,實(shí)際上是注冊(cè)到DataSetObservable中
            mAdapter.registerDataSetObserver(mDataSetObserver);
            //代碼省略 
        } else {
           //代碼省略
         }
        requestLayout();
    }

從程序可以看到,在設(shè)置Adapter的時(shí)會(huì)構(gòu)建一個(gè)AdapterDataSetObserver,這就是上面說(shuō)的觀察者,最后將這個(gè)觀察者注冊(cè)到了Adapter,這樣我們的被觀察者、觀察者就都有了;
那么AdapterDataSetObserver是什么?它如何運(yùn)作?那么現(xiàn)在來(lái)看看,AdapterDataObserver定義在ListView的父類(lèi)AbsListView中,具體代碼如下:

 class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }

它又繼承自AbsListView的父類(lèi)AdapterView的AdapterDataSetObserver,具體代碼如下:

class AdapterDataSetObserver extends DataSetObserver {
        private Parcelable mInstanceState = null;

    //調(diào)用Adapter的notifyDataSetChanged的時(shí)會(huì)調(diào)用所有觀察者的onChanged()方法,核心就是這里
      @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();
        }

      //代碼省略

    public void clearSavedState() {
            mInstanceState = null;
        }
}

到這里就知道了,當(dāng)ListView的數(shù)據(jù)發(fā)生變化時(shí),調(diào)用Adapter的notifyDataSetChanged(),這個(gè)方法又調(diào)用了DataSetObservable的notifyChanged()方法,這個(gè)方法會(huì)調(diào)用所有觀察者AdapterDataSetObserver的onChanged(),在onChanged函數(shù)中又會(huì)調(diào)用ListView重新布局的函數(shù)和使得ListView刷新界面,這就是一個(gè)觀察者模式;
現(xiàn)在再整理一下這個(gè)過(guò)程,AdapterView中又一個(gè)內(nèi)部類(lèi)AdapterDataSetObserver,在ListView設(shè)置Adapter時(shí)會(huì)構(gòu)建一個(gè)AdapterDataSetObserver,并且注冊(cè)到Adapter中,這就是一個(gè)觀察者。而Adapter中有一個(gè)數(shù)據(jù)集被觀察者DataSetObservable,在數(shù)據(jù)數(shù)量發(fā)生變更時(shí),開(kāi)發(fā)者手動(dòng)調(diào)用Adapter.notifyDataSetChanged(),而notifyDataSetChanged()實(shí)際上是調(diào)用DataObservable的notifyChanged()方法,該方法會(huì)遍歷所有的觀察者的onChanged()。在AdapterDataSetObserver的onChanged()會(huì)獲取Adpaer中數(shù)據(jù)集的新數(shù)量,然后調(diào)用ListView的requestLayout()方法重新進(jìn)行布局,更新用戶(hù)界面。

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

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

  • Android 架構(gòu)師之路 目錄 1、觀察者模式概念 1.1 介紹 當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(O...
    香沙小熊閱讀 1,744評(píng)論 1 2
  • 一、觀察者模式的定義 定義對(duì)象間一對(duì)多的依賴(lài)關(guān)系,使得當(dāng)前對(duì)象改變了狀態(tài),則所有依賴(lài)于它的對(duì)象都會(huì)得到通知并自動(dòng)更...
    sssssss_閱讀 631評(píng)論 0 0
  • 參考 《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ) 》5.7 Observer 觀察者 對(duì)象行為型模式 《設(shè)計(jì)模式解析》 ...
    WangGavin閱讀 593評(píng)論 0 2
  • 1 定義 定義對(duì)象之間的一種一對(duì)多依賴(lài)關(guān)系,使得每當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變時(shí),其相關(guān)依賴(lài)對(duì)象皆得到通知并被自動(dòng)更新。...
    菜小軒526閱讀 595評(píng)論 3 3
  • 有時(shí)候,我還是會(huì)想起若曦。她現(xiàn)在會(huì)是什么樣子?一定還是那個(gè)樣子。她就像是那種不會(huì)被歲月變老的女孩。 “我是妖精變的...
    又見(jiàn)光明閱讀 839評(píng)論 1 2

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