一個(gè)簡單的demo徹底搞懂觀察者模式

介紹

觀察者模式也被稱為發(fā)布-訂閱(Publish/Subscribe)模式尤仍,它屬于行為型模式的一種。觀察者模式定義了一種一對多的依賴關(guān)系窜管,一個(gè)主題對象可被多個(gè)觀察者對象同時(shí)監(jiān)聽揩尸。當(dāng)這個(gè)主題對象狀態(tài)變化時(shí)宛渐,會(huì)通知所有觀察者對象并作出相應(yīng)處理邏輯界斜。

UML

觀察者模式UML

觀察者模式定義了四種角色:抽象主題仿耽、具體主題、抽象觀察者各薇、具體觀察者项贺。

  1. 抽象主題(Subject):該角色是一個(gè)抽象類或接口,定義了增加得糜、刪除敬扛、通知觀察者對象的方法。
  2. 具體主題(ConcreteSubject):該角色繼承或?qū)崿F(xiàn)了抽象主題朝抖,定義了一個(gè)集合存入注冊過的具體觀察者對象啥箭,在具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),給所有注冊過的觀察者發(fā)送通知治宣。
  3. 抽象觀察者(Observer):該角色是具體觀察者的抽象類急侥,定義了一個(gè)更新方法。
  4. 具體觀察者(ConcrereObserver):該角色是具體的觀察者對象侮邀,在得到具體主題更改通知時(shí)更新自身的狀態(tài)坏怪。
    </br>
    </br>

實(shí)現(xiàn)代碼

抽象觀察者(Observer)接口

public interface Observer {

     public void update(String msg, TextView tv);
}

具體觀察者(Person)類

public class Person implements Observer {

    // 用戶名
    private String name;
    public Person(String name) {
        this.name = name;
    }

    @Override
    public void update(String msg, TextView tv) {
        tv.setText(tv.getText()+name+":"+ msg +"\n");
    }
    
}

抽象主題(Subject)接口

public interface Subject {
    /**
     * 增加觀察者
     * @param observer
     */
    public void attach(Observer observer);
    /**
     * 刪除觀察者
     * @param observer
     */
    public void detach(Observer observer);
    /**
     * 通知觀察者
     */
    public void notify(String message, TextView v);
}

具體主題(XiaosongSubject)類

public class XiaosongSubject implements Subject {

    //用于保存訂閱了小嵩的博客的用戶
    private List<Observer> mPersonList = new ArrayList<>();

    @Override
    public void attach(Observer observer) {
        mPersonList.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        mPersonList.remove(observer);
    }

    @Override
    public void notify(String message, TextView tv) {
        for (Observer observer : mPersonList) {
            observer.update(message,tv);
        }
    }
}

MainActivity類

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Person pMing,pQing,pLiang;
    private XiaosongSubject mSubject;

    private TextView tv_output;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initEvent();
    }

    private void initView() {

        findViewById(R.id.btn_add_one).setOnClickListener(this);
        findViewById(R.id.btn_add_two).setOnClickListener(this);
        findViewById(R.id.btn_add_three).setOnClickListener(this);

        findViewById(R.id.btn_notify).setOnClickListener(this);
        findViewById(R.id.btn_delete).setOnClickListener(this);

        tv_output = (TextView)findViewById(R.id.tv_output);
    }

    private void initEvent() {
        //創(chuàng)建被觀察者(具體主題)
        mSubject = new XiaosongSubject();
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_add_one://注冊觀察者 小明
                if (pMing==null){
                    pMing = new Person("小明");
                    mSubject.attach(pMing);
                    Toast.makeText(this,"小明關(guān)注了我",Toast.LENGTH_SHORT).show();
                }else {
                    Toast.makeText(this,"小明已關(guān)注我了,不能再重復(fù)操作",Toast.LENGTH_SHORT).show();
                }
                break;

            case R.id.btn_add_two://注冊觀察者 小琴
                if (pQing==null){
                    pQing = new Person("小琴");
                    mSubject.attach(pQing);
                    Toast.makeText(this,"小琴關(guān)注了我",Toast.LENGTH_SHORT).show();
                }else {
                    Toast.makeText(this,"小琴已關(guān)注我了绊茧,不能再重復(fù)操作",Toast.LENGTH_SHORT).show();
                }
                break;

            case R.id.btn_add_three://注冊觀察者 阿亮
                if (pLiang==null){
                    pLiang = new Person("阿亮");
                    mSubject.attach(pLiang);
                    Toast.makeText(this,"阿亮關(guān)注了我",Toast.LENGTH_SHORT).show();
                }else {
                    Toast.makeText(this,"阿亮已關(guān)注我了铝宵,不能再重復(fù)操作",Toast.LENGTH_SHORT).show();
                }
                break;

            case R.id.btn_notify://主題(被觀察者)更新了內(nèi)容,通知所有觀察者
                tv_output.setText("");
                mSubject.notify("小嵩更新微博啦~ 快來看看吧", tv_output);
                break;

            case R.id.btn_delete://注銷觀察者 小明
                if (pMing!=null){
                    mSubject.detach(pMing);
                    pMing = null;
                }

                if (pQing!=null){//注銷觀察者 小琴
                    mSubject.detach(pQing);
                    pQing = null;
                }

                if (pLiang!=null){//注銷觀察者 阿亮
                    mSubject.detach(pLiang);
                    pLiang = null;
                }

                break;

            default:
                break;
        }
    }
}

總結(jié)

在Android中华畏,有很多場景使用了觀察者模式鹏秋,比如Android的源碼里:OnClickListener、ContentObserver亡笑、android.database.Observable等侣夷;還有第三方開源庫EventBus、RxJava仑乌、RxAndroid等百拓。具體可閱讀它們的源碼去理解和體會(huì)。這里我寫了一個(gè)簡單的demo晰甚,以便對它有更加深刻的理解衙传,覺得這篇文章有用的話,可以點(diǎn)個(gè)贊哦~

GitHub的示例項(xiàng)目鏈接地址:ObserverPatternDemo

這里寫圖片描述
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末厕九,一起剝皮案震驚了整個(gè)濱河市粪牲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌止剖,老刑警劉巖腺阳,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件落君,死亡現(xiàn)場離奇詭異,居然都是意外死亡亭引,警方通過查閱死者的電腦和手機(jī)绎速,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焙蚓,“玉大人纹冤,你說我怎么就攤上這事」汗” “怎么了萌京?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宏浩。 經(jīng)常有香客問我知残,道長,這世上最難降的妖魔是什么比庄? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任求妹,我火速辦了婚禮,結(jié)果婚禮上佳窑,老公的妹妹穿的比我還像新娘制恍。我一直安慰自己,他們只是感情好神凑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布净神。 她就那樣靜靜地躺著,像睡著了一般溉委。 火紅的嫁衣襯著肌膚如雪鹃唯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天薛躬,我揣著相機(jī)與錄音,去河邊找鬼呆细。 笑死型宝,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的絮爷。 我是一名探鬼主播趴酣,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坑夯!你這毒婦竟也來了岖寞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤柜蜈,失蹤者是張志新(化名)和其女友劉穎仗谆,沒想到半個(gè)月后指巡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隶垮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年藻雪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狸吞。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勉耀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蹋偏,到底是詐尸還是另有隱情便斥,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布威始,位于F島的核電站枢纠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏字逗。R本人自食惡果不足惜京郑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望葫掉。 院中可真熱鬧些举,春花似錦、人聲如沸俭厚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挪挤。三九已至叼丑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扛门,已是汗流浹背鸠信。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留论寨,地道東北人星立。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像葬凳,于是被迫代替她去往敵國和親绰垂。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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

  • 設(shè)計(jì)模式匯總 一火焰、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用劲装、多...
    MinoyJet閱讀 3,939評論 1 15
  • 1 場景問題# 1.1 訂閱報(bào)紙的過程## 來考慮實(shí)際生活中訂閱報(bào)紙的過程,這里簡單總結(jié)了一下,訂閱報(bào)紙的基本流程...
    七寸知架構(gòu)閱讀 4,620評論 5 57
  • 本文的結(jié)構(gòu)如下: 什么是觀察者模式 為什么要用該模式 模式的結(jié)構(gòu) 代碼示例 推模型和拉模型 優(yōu)點(diǎn)和缺點(diǎn) 適用環(huán)境 ...
    w1992wishes閱讀 1,435評論 0 16
  • 設(shè)計(jì)模式基本原則 開放-封閉原則(OCP)占业,是說軟件實(shí)體(類绒怨、模塊、函數(shù)等等)應(yīng)該可以拓展纺酸,但是不可修改窖逗。開-閉原...
    西山薄涼閱讀 3,792評論 3 14
  • 選紅木三要素用的安心買的開心 在選購紅木的時(shí)候,我們總是斟酌再三餐蔬。生怕選到的紅木家具不是好的碎紊,不是自己意想中的樣子...
    wenddy閱讀 139評論 0 0