java/android設(shè)計(jì)模式-行為模式之觀察者模式

祝大家雞年大吉。。物蝙。吧
觀察者模式是對象的行為模式,又叫發(fā)布-訂閱(Publish/Subscribe)模式敢艰、模型-視圖(Model/View)模式专肪、源-監(jiān)聽器(Source/Listener)模式或從屬者(Dependents)模式因妙。

觀察者模式定義了一種一對多的依賴關(guān)系笆豁,讓多個觀察者對象同時監(jiān)聽某一個主題對象徽诲。這個主題對象在狀態(tài)上發(fā)生變化時,會通知所有觀察者對象牡属,使它們能夠自動更新自己票堵。

所謂觀察者模式

一個軟件系統(tǒng)常常要求在某一個對象的信息發(fā)生變化的時候,某些其他的對象做出相應(yīng)的改變逮栅。做到這一點(diǎn)的設(shè)計(jì)方案有很多悴势,但是為了使系統(tǒng)能夠易于復(fù)用,應(yīng)該選擇低耦合度的設(shè)計(jì)方案措伐。減少對象之間的耦合有利于系統(tǒng)的復(fù)用特纤,但是同時設(shè)計(jì)師需要使這些低耦合度的對象之間能夠維持行動的協(xié)調(diào)一致,保證高度的協(xié)作侥加。觀察者模式是滿足這一要求的各種設(shè)計(jì)方案中最重要的一種捧存。
下面看看觀察者模式的結(jié)構(gòu):

  • 抽象主題(Subject)角色:抽象主題角色把所有對觀察者對象的引用保存在一個聚集(比如ArrayList對象)里,每個主題都可以有任何數(shù)量的觀察者担败。抽象主題提供一個接口矗蕊,可以增加和刪除觀察者對象,抽象主題角色又叫做抽象被觀察者(Observable)角色氢架。
  • 具體主題(ConcreteSubject)角色:將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時朋魔,給所有登記過的觀察者發(fā)出通知岖研。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。
  • 抽象觀察者(Observer)角色:為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己孙援,這個接口叫做更新接口害淤。
  • 具體觀察者(ConcreteObserver)角色: ** 存儲與主題的狀態(tài)自恰的狀態(tài)。具體觀察者角色實(shí)現(xiàn)抽象觀察者角色所要求的更新接口拓售,以便使本身的狀態(tài)與主題的狀態(tài) 像協(xié)調(diào)窥摄。如果需要,具體觀察者角色可以保持一個指向具體主題對象的引用础淤。
    在觀察者模式中又分為
    推模型拉模型**:
  • 推模型
    主題對象向觀察者推送主題的詳細(xì)信息崭放,不管觀察者是否需要,推送的信息通常是主題對象的全部或部分?jǐn)?shù)據(jù)鸽凶。
  • 拉模型
    主題對象在通知觀察者的時候币砂,只傳遞少量信息。如果觀察者需要更具體的信息玻侥,由觀察者主動到主題對象中獲取决摧,相當(dāng)于是觀察者從主題對象中拉數(shù)據(jù)。一般這種模型的實(shí)現(xiàn)中凑兰,會把主題對象自身通過update()方法傳遞給觀察者掌桩,這樣在觀察者需要獲取數(shù)據(jù)的時候,就可以通過這個引用來獲取了姑食。
    可能單單這樣說概念會覺得模糊波岛,還是有代碼說明吧。

推模型源碼

抽象subject類:

public abstract class Subject {
    /**
     * 用來保存注冊的觀察者對象
     */
    private List<Observer> list = new ArrayList<Observer>();
    /**
     * 注冊觀察者對象
     * @param observer    觀察者對象
     */
    public void attach(Observer observer){

        list.add(observer);
        System.out.println("Attached an observer");
    }
    /**
     * 刪除觀察者對象
     * @param observer    觀察者對象
     */
    public void detach(Observer observer){

        list.remove(observer);
    }
    /**
     * 通知所有注冊的觀察者對象
     */
    public void nodifyObservers(String newState){

        for(Observer observer : list){
            observer.update(newState);
        }
    }
}

具體的subject類:

public class ConcreteSubject extends Subject {

    private String state;

    public String getState() {
        return state;
    }

    public void change(String newState){
        state = newState;
        System.out.println("修改主題狀態(tài)為:" + state);
        //狀態(tài)發(fā)生改變矢门,通知各個觀察者
        this.nodifyObservers(state);
    }
}

抽象觀察者類:

public interface Observer {
    /**
     * 更新接口
     * @param state    更新的狀態(tài)
     */
    public void update(String state);
}

具體的觀察者:

public class ConcreteObserver implements Observer {
    //觀察者的狀態(tài)
    private String observerState;
    
    @Override
    public void update(String state) {
        /**
         * 更新觀察者的狀態(tài)盆色,使其與目標(biāo)的狀態(tài)保持一致
         */
        observerState = state;
        System.out.println("狀態(tài)為:"+observerState);
    }
}

測試類:

public class Client {
    public static void main(String[] args) {
        //創(chuàng)建主題對象
        ConcreteSubject subject = new ConcreteSubject();
        //創(chuàng)建觀察者對象
        Observer observer = new ConcreteObserver();
        //將觀察者對象登記到主題對象上
        subject.attach(observer);
        //改變主題對象的狀態(tài)
        subject.change("new state");
    }
}

結(jié)果:

Attached an observer
修改主題狀態(tài)為:new state
觀察者的狀態(tài)為:new state

拉模型源碼

與推模型不同的地方在與:拉模型通常都是把主題對象當(dāng)作參數(shù)傳遞。

public interface Observer {
    /**
     * 更新接口
     * @param subject 傳入主題對象祟剔,方面獲取相應(yīng)的主題對象的狀態(tài)
     */
    public void update(Subject subject);
}

在具體觀察者實(shí)現(xiàn)的地方:

  @Override
    public void update(Subject subject) {
        /**
         * 更新觀察者的狀態(tài)隔躲,使其與目標(biāo)的狀態(tài)保持一致
         */
        observerState = ((ConcreteSubject)subject).getState();
        System.out.println("觀察者狀態(tài)為:"+observerState);
    }

subject的 nodifyObservers(String newState)變成:

 public void nodifyObservers(){
        
        for(Observer observer : list){
            observer.update(this);
        }
    }

兩種模式的比較

  • 推模型是假定主題對象知道觀察者需要的數(shù)據(jù);而拉模型是主題對象不知道觀察者具體需要什么數(shù)據(jù)物延,沒有辦法的情況下宣旱,干脆把自身傳遞給觀察者,讓觀察者自己去按需要取值叛薯。
  • 推模型可能會使得觀察者對象難以復(fù)用浑吟,因?yàn)橛^察者的update()方法是按需要定義的參數(shù),可能無法兼顧沒有考慮到的使用情況耗溜。這就意味著出現(xiàn)新情況的時候组力,就可能提供新的update()方法,或者是干脆重新實(shí)現(xiàn)觀察者抖拴;而拉模型就不會造成這樣的情況燎字,因?yàn)槔P拖滦冉罚瑄pdate()方法的參數(shù)是主題對象本身,這基本上是主題對象能傳遞的最大數(shù)據(jù)集合了候衍,基本上可以適應(yīng)各種情況的需要笼蛛。

android的使用觀察者模式

其中我們可能在日常開發(fā)中每天都在用的就是adapter.notifyDataSetChanged()
BaseAdapter中:

 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是android.database.Observable<DataSetObserver>的子類

DataSetObservable extends Observable<DataSetObserver>

mDataSetObservable.notifyChanged();的源碼:

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

具體要實(shí)現(xiàn)怎么樣的邏輯可繼承DataSetObserver對應(yīng)的方法。
當(dāng)然還有更常用的View.setOnClickListener( )的事件注冊蛉鹿。用到觀察者模型的地方很多滨砍。
其次再說說的就是就是我們或多或少有過接觸的三方框架EventBus和RxJava,它們都是基于觀察者模式實(shí)現(xiàn)的。
RxJava要比EventBus的應(yīng)用更廣泛妖异,EventBus僅僅是作為一種消息的傳遞工具惋戏,但是RxJava里面幾乎可以做任何事情,只是對于簡單的業(yè)務(wù)來說可能有些冗余随闺,EventBus相對來說更加輕量日川,EventBus有個缺點(diǎn)就是凡是使用了EventBus的類都不能進(jìn)行混淆了,否則Evnetbus就找不到OnEvent方法了矩乐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末龄句,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子散罕,更是在濱河造成了極大的恐慌分歇,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欧漱,死亡現(xiàn)場離奇詭異职抡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)误甚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門缚甩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窑邦,你說我怎么就攤上這事擅威。” “怎么了冈钦?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵郊丛,是天一觀的道長。 經(jīng)常有香客問我瞧筛,道長厉熟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任较幌,我火速辦了婚禮揍瑟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乍炉。我一直安慰自己月培,他們只是感情好嘁字,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杉畜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衷恭。 梳的紋絲不亂的頭發(fā)上此叠,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機(jī)與錄音随珠,去河邊找鬼灭袁。 笑死,一個胖子當(dāng)著我的面吹牛窗看,可吹牛的內(nèi)容都是我干的茸歧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼显沈,長吁一口氣:“原來是場噩夢啊……” “哼软瞎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拉讯,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤涤浇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后魔慷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體只锭,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年院尔,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜻展。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡邀摆,死狀恐怖纵顾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情隧熙,我是刑警寧澤片挂,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贞盯,受9級特大地震影響音念,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜躏敢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一闷愤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧件余,春花似錦讥脐、人聲如沸遭居。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俱萍。三九已至,卻和暖如春告丢,著一層夾襖步出監(jiān)牢的瞬間枪蘑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工岖免, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岳颇,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓颅湘,卻偏偏與公主長得像话侧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闯参,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1 場景問題# 1.1 訂閱報紙的過程## 來考慮實(shí)際生活中訂閱報紙的過程瞻鹏,這里簡單總結(jié)了一下,訂閱報紙的基本流程...
    七寸知架構(gòu)閱讀 4,622評論 5 57
  • 面向?qū)ο蟮牧笤瓌t 單一職責(zé)原則 所謂職責(zé)是指類變化的原因赢赊。如果一個類有多于一個的動機(jī)被改變乙漓,那么這個類就具有多于...
    JxMY閱讀 943評論 1 3
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)释移,斷路器叭披,智...
    卡卡羅2017閱讀 134,667評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法玩讳,內(nèi)部類的語法涩蜘,繼承相關(guān)的語法,異常的語法熏纯,線程的語...
    子非魚_t_閱讀 31,643評論 18 399
  • 剛乘車路過盧溝橋 不敢抬頭看著那橋 因太多沈重我們無法面對 因太多苦痛我們無法想像 但我們今天也許有人依然不醒 理...
    哈皮皮皮閱讀 295評論 0 0