Java設(shè)計模式--觀察者模式

什么是觀察者模式

觀察者模式定義了對象之間的一對多關(guān)系,當(dāng)一個對象改變狀態(tài)時,它的所有依賴者都會收到通知并自動更新。

模擬現(xiàn)實中的一種需求

  • 報社出版了人民日報潜索,
    1. AB都在報社訂閱了人民日報
    2. 這個時候C也想訂一份人民日報臭增,報社說那好,你交錢我就給你訂上帮辟,以后我每期人民日報你都可以收到,C交了錢玩焰,訂了報紙由驹。
    3. 以后每天AB昔园、C都會在門口拿到一份人民日報蔓榄。
    4. 后來B覺得看報紙沒什么意思,就跟報社說不想訂了默刚,你把錢退給我吧甥郑,報社說行,錢退給你荤西,訂閱名單里邊就沒有你了澜搅,以后就不給你報紙了。
    5. 只要報社正常經(jīng)營邪锌,會有越來越多的ABC勉躺。

實現(xiàn)方法

  • 開始時A、B訂閱了報紙觅丰,代碼大概是這樣
public class 報社 {
    String  報紙;
    
    //報社本身屬性饵溅。。妇萄。蜕企。
    
    //假設(shè)每次新出報紙會調(diào)用這個方法
    public void onPublic(){
        a.門口拿包裝紙(報紙);
        b.門口拿包裝紙(報紙);
    }
}

public class A {
    public void 門口拿報紙(String 報紙){
        System.out.println("看國家大事");
    }
}

public class B {
    public void 門口拿報紙(String 報紙){
        System.out.println("看娛樂新聞!9诰洹轻掩!");
    }
}
  • C也想看報紙,所以接著寫
public class 報社 {
    String  報紙;
    
    //報社本身屬性懦底。放典。。基茵。
    
    //假設(shè)每次新出報紙會調(diào)用這個方法
    public void onPublic(){
        a.門口拿包裝紙(報紙);
        b.門口拿包裝紙(報紙);
        c.門口拿包裝紙(報紙);
    }
}

public class C {
    public void 門口拿報紙(String 報紙){
        System.out.println("看新發(fā)地菜價7芄埂!");
    }
}
  • B又不想訂報紙了拱层,那就把B注釋掉
public class 報社 {
    String  報紙;
    
    //報社本身屬性弥臼。。根灯。径缅。
    
    //假設(shè)每次新出報紙會調(diào)用這個方法
    public void onPublic(){
        a.門口拿包裝紙(報紙);
        //b.門口拿包裝紙(報紙);
        c.門口拿包裝紙(報紙);
    }
}
  • 當(dāng)ABC越來越多的時候代碼就會成了這樣
public class 報社 {
    String  報紙;
    
    //報社本身屬性掺栅。。纳猪。氧卧。
    
    //每次新出報紙會調(diào)用這個方法
    public void onPublic(){
        a.門口拿包裝紙(報紙);
//      b.門口拿包裝紙(報紙);
        c.門口拿包裝紙(報紙);
        d.門口拿包裝紙(報紙);
        e.門口拿包裝紙(報紙);
//      f.門口拿包裝紙(報紙);
        g.門口拿包裝紙(報紙);
        h.門口拿包裝紙(報紙);
//      i.門口拿包裝紙(報紙);
        j.門口拿包裝紙(報紙);
        k.門口拿包裝紙(報紙);
        ...
    }
}
  • 所以,正如你看到的
    1. 對于每一個想訂閱報紙的人氏堤,我們都要修改代碼
    2. 無法在運行的時候動態(tài)的增加或者刪除觀察者(訂閱報紙的人)
    3. 針對的是具體實現(xiàn)編程沙绝,并不是針對接口編程
    4. 沒有封裝改變的部分

OK,報社改個名稱叫Observable鼠锈,ABC改個名稱叫Observer闪檬,知道怎么訂報紙就知道什么是觀察者模式了。

明確三個關(guān)鍵詞购笆,Observable(被觀察者)粗悯、subscribe(訂閱)、Observer(觀察者)同欠。Observable(報社)是一個有各種狀態(tài)的對象样傍,Observer(A、B铺遂、C)subscribe(訂閱)了Observable(報社)

那就用觀察者模式來實現(xiàn)一下上面的需求铭乾,實現(xiàn)觀察者模式的方法不止一種,最常見的就是實現(xiàn)Observabe和Observer接口娃循,下面具體實現(xiàn)炕檩,對比看一下優(yōu)點。

觀察者模式接口實現(xiàn)

  • Observable
public interface Observable {
    void registerObserver(Observer o);
    void removeObserver(Observer  o);
    //更新狀態(tài)的時候會掉用這個方法
    void notifyObserver();
}
  • Observer
public interface Observer {
    void 門口看報紙(String 報紙);
}
  • 接下來讓報社這個類實現(xiàn)Observable接口捌斧,ABC實現(xiàn)Observer接口
public class 報社 implements Observable {
    private List<Observer> observers;
    String  報紙;
    
    public 報社() {
        observers = new ArrayList<>();
    }
    
    @Override
    public void notifyObserver() {
        for(Observer o:observers){
            o.門口看報紙(報紙);
        }
        
    }
    
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
        
    }
    
    @Override
    public void removeObserver(Observer o) {
        int index = observers.indexOf(o);
        if(index>0){
            observers.remove(index);
        }
    }
}
public class A implements Observer{
    
    @Override
    public void 門口看報紙(String 報紙) {
        System.out.println("看國家大事");
        
    }
}
  • 接下來就是訂報紙
public class Test {

    public static void main(String[] args) {
        報社 test = new 報社();
        A a =new A();
        B b = new B();
        //a 添加訂閱
        test.registerObserver(a);
        //b 添加訂閱
        test.registerObserver(b);
        //c 添加訂閱
        test.registerObserver(c);
        //b 移除訂閱
        test.removeObserver(b);
    }
}
  • 所以笛质,正如你看到的
    1. 對于每一個想訂閱報紙的人,我們不需要修改代碼捞蚂,只要實現(xiàn)了Observer接口后registerObserver就好了妇押。
    2. <del>無法</del><mark>隨意</mark>在運行的時候動態(tài)的增加或者刪除觀察者(訂閱報紙的人)
    3. 針對的是<del>具體實現(xiàn)</del><mark>接口</mark>編程,并不是針對<del>接口</del><mark>具體實現(xiàn)</mark>編程
    4. <del>沒有</del>封裝改變的部分

結(jié)束語

觀察者模式在JDK就有實現(xiàn)姓迅,只不過是用類實現(xiàn)的敲霍,需要繼承,眾所周知丁存,java是單繼承的肩杈,所以有一定的黑暗面。另外解寝,Java swing 中的JButton扩然、Android中給Button設(shè)置OnClickListenner以及現(xiàn)在非常火的RxJava都是觀察者模式的實現(xiàn)聋伦,有興趣的可以看看源碼夫偶,OK就到這里了界睁,歡迎指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兵拢,一起剝皮案震驚了整個濱河市翻斟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌说铃,老刑警劉巖访惜,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異截汪,居然都是意外死亡疾牲,警方通過查閱死者的電腦和手機植捎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門衙解,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人焰枢,你說我怎么就攤上這事蚓峦。” “怎么了济锄?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵暑椰,是天一觀的道長。 經(jīng)常有香客問我荐绝,道長一汽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任低滩,我火速辦了婚禮召夹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恕沫。我一直安慰自己监憎,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布婶溯。 她就那樣靜靜地躺著鲸阔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迄委。 梳的紋絲不亂的頭發(fā)上褐筛,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音叙身,去河邊找鬼死讹。 笑死,一個胖子當(dāng)著我的面吹牛曲梗,可吹牛的內(nèi)容都是我干的赞警。 我是一名探鬼主播妓忍,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼愧旦!你這毒婦竟也來了世剖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤笤虫,失蹤者是張志新(化名)和其女友劉穎旁瘫,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琼蚯,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡酬凳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了遭庶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宁仔。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖峦睡,靈堂內(nèi)的尸體忽然破棺而出翎苫,到底是詐尸還是另有隱情,我是刑警寧澤榨了,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布煎谍,位于F島的核電站,受9級特大地震影響龙屉,放射性物質(zhì)發(fā)生泄漏呐粘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一转捕、第九天 我趴在偏房一處隱蔽的房頂上張望作岖。 院中可真熱鬧,春花似錦瓜富、人聲如沸鳍咱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谤辜。三九已至,卻和暖如春价捧,著一層夾襖步出監(jiān)牢的瞬間丑念,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工结蟋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脯倚,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像推正,于是被迫代替她去往敵國和親恍涂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

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