無處不在的觀察者模式

觀察者模式

觀察者模式是使用率非常高的一種設(shè)計(jì)模式。

什么是觀察模式俄讹?
對象間存在一對多的依賴關(guān)系疫衩,需要在某個(gè)對象改變的時(shí)候,依賴于該對象的所有其他對象都收到通知并進(jìn)行更新和相應(yīng)的業(yè)務(wù)操作剑鞍。

簡而言之,就是當(dāng)一個(gè)被觀察的對象改變了就要去通知它的觀察者爽醋,告訴觀察者我有變化了蚁署,你可以進(jìn)行你需要的處理操作。

無處不在的觀察者
情景一:小明(觀察者)給媽媽說飯熟了叫我吃飯蚂四,媽媽(被觀察者)等到飯熟了就會(huì)通知小明來吃飯了光戈。
情景二:代碼中有個(gè)需求需要監(jiān)聽用戶打開藍(lán)牙就關(guān)掉藍(lán)牙。這肯定需要使用觀察者模式遂赠,監(jiān)聽到藍(lán)牙打開了久妆,就通知相應(yīng)的觀察者,然后做關(guān)掉藍(lán)牙的操作跷睦。

觀察者模式的作用就是使對象解耦筷弦,將觀察者和被觀察者完全隔離。上述情景抑诸,小明可以在媽媽做飯的時(shí)候?qū)懽鳂I(yè)烂琴,等媽媽叫她吃飯的時(shí)候再去吃飯。這樣小明和媽媽就可以各干各的事情哼鬓,完全解耦。

最簡單的觀察者模式Demo

項(xiàng)目結(jié)構(gòu)如下边灭,只有4個(gè)類超級簡單异希。

代碼結(jié)構(gòu).jpg
  • 被觀察接口,三個(gè)方法绒瘦,注冊監(jiān)聽者称簿,注銷監(jiān)聽者,通知所有觀察者
/**
 * 被觀察者接口
 */
public interface IObservable {

    void registerObserver(IObserver observer);

    void unregisterObserver(IObserver observer);

    void notifyAllObservers();

}
  • 觀察者接口:更新數(shù)據(jù)
/**
 * 觀察者接口
 */
public interface IObserver {
    void update();
}
  • 觀察者實(shí)現(xiàn)類
/**
 * 觀察者實(shí)現(xiàn)類
 */
public class ObserverImpl implements IObserver{

    private static final String TAG = "ObserverImpl";
    private String observerName;

    public ObserverImpl(String observerName){
        this.observerName = observerName;
    }
    @Override
    public void update() {
        Log.i(TAG,observerName +"數(shù)據(jù)更新了----->");
    }
}
  • 被觀察者實(shí)現(xiàn)類
/**
 * 被觀察者實(shí)現(xiàn)類
 */
public class ObservableImpl implements IObservable{

    private List<IObserver> mObserversList = new ArrayList<>();//注冊的所有觀察者集合
    @Override
    public void registerObserver(IObserver observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObserversList) {
            if (mObserversList.contains(observer)) {
                throw new IllegalStateException("Observer " + observer + " is already registered.");
            }
            mObserversList.add(observer);
        }
    }

    @Override
    public void unregisterObserver(IObserver observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
       synchronized(observer) {
            int index = mObserversList.indexOf(observer);
            if (index == -1) {
                throw new IllegalStateException("Observer " + observer + " was not registered.");
            }
            mObserversList.remove(index);
        }
    }

    @Override
    public void notifyAllObservers() {
        for(int i = 0;i < mObserversList.size(); i++){
            IObserver observer = mObserversList.get(i);
            observer.update();
        }
    }
}

其實(shí)看了被觀察者的實(shí)現(xiàn)惰帽,原來所謂的注冊監(jiān)聽和取消監(jiān)聽都是靠一個(gè)list集合來維護(hù)憨降,最后的通知觀察者的本質(zhì)也就是遍歷這個(gè)list集合,然后調(diào)用觀察者的update方法该酗。

  • 測試demo
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ObserverImpl observer1 = new ObserverImpl("觀察者 1 :");
        ObserverImpl observer2 = new ObserverImpl("觀察者 2 :");

        ObservableImpl observable = new ObservableImpl();//被觀察者
        observable.registerObserver(observer1);
        observable.registerObserver(observer2);

    //  observable.unregisterObserver(observer2);
        
        observable.notifyAllObservers();
    }
}
  • 測試結(jié)果:
1.jpg

我們可以從結(jié)果看出注冊的2個(gè)觀察者都收到數(shù)據(jù)更新的消息了授药。這就是目前演示的最簡單的觀察者模式的寫法士嚎。

觀察者模式在Android源碼中的使用:

  • 四大組件其中一個(gè):Broadcast其實(shí)就是一個(gè)訂閱發(fā)布的觀察者模式。我們注冊廣播接收者registerReceiver悔叽,當(dāng)sendBroadcast的發(fā)送廣播時(shí)莱衩,onReceive 方法就會(huì)被調(diào)用。這是一個(gè)非常典型的觀察者模式娇澎。onReceive方法就類似于上述例子中的觀察者接口中的update()方法笨蚁。細(xì)細(xì)想來,其實(shí)我們見過的很多代碼其實(shí)使用的就是觀察者模式趟庄。
    -其實(shí)ListView使用Adapter模式也是觀察者模式
    我們在使用ListView的時(shí)候會(huì)使用到一個(gè)方法notifyDataSetChanged();每當(dāng)有數(shù)據(jù)源更新括细,調(diào)用該方法就可以更新頁面。notifyDataSetChanged()源碼其實(shí)和上述的被觀察者實(shí)現(xiàn)類里面 notifyAllObservers()的方法類似戚啥。

Android源碼其實(shí)就是一個(gè)很好的學(xué)習(xí)的例子奋单,我們平時(shí)使用的很多模式在源碼中都有體現(xiàn)。觀察者模式是我們必現(xiàn)要掌握的設(shè)計(jì)模式之一虑鼎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辱匿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子炫彩,更是在濱河造成了極大的恐慌匾七,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件江兢,死亡現(xiàn)場離奇詭異昨忆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)杉允,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門邑贴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人叔磷,你說我怎么就攤上這事拢驾。” “怎么了改基?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵繁疤,是天一觀的道長。 經(jīng)常有香客問我秕狰,道長稠腊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任鸣哀,我火速辦了婚禮架忌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘我衬。我一直安慰自己叹放,他們只是感情好饰恕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著许昨,像睡著了一般懂盐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上糕档,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天莉恼,我揣著相機(jī)與錄音,去河邊找鬼速那。 笑死俐银,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的端仰。 我是一名探鬼主播捶惜,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼荔烧!你這毒婦竟也來了吱七?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤鹤竭,失蹤者是張志新(化名)和其女友劉穎踊餐,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體臀稚,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吝岭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吧寺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窜管。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖稚机,靈堂內(nèi)的尸體忽然破棺而出幕帆,到底是詐尸還是另有隱情,我是刑警寧澤赖条,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布失乾,位于F島的核電站,受9級特大地震影響谋币,放射性物質(zhì)發(fā)生泄漏仗扬。R本人自食惡果不足惜症概,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一蕾额、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彼城,春花似錦诅蝶、人聲如沸退个。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽语盈。三九已至,卻和暖如春缰泡,著一層夾襖步出監(jiān)牢的瞬間刀荒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工棘钞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缠借,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓宜猜,卻偏偏與公主長得像泼返,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子姨拥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

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