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

什么是觀察者模式

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

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

  • 報社出版了人民日報,
    1. AB都在報社訂閱了人民日報
    2. 這個時候C也想訂一份人民日報,報社說那好,你交錢我就給你訂上,以后我每期人民日報你都可以收到,C交了錢,訂了報紙。
    3. 以后每天A、BC都會在門口拿到一份人民日報。
    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("看娛樂新聞?。?!");
    }
}
  • C也想看報紙,所以接著寫
public class 報社 {
    String  報紙;
    
    //報社本身屬性。。。。
    
    //假設(shè)每次新出報紙會調(diào)用這個方法
    public void onPublic(){
        a.門口拿包裝紙(報紙);
        b.門口拿包裝紙(報紙);
        c.門口拿包裝紙(報紙);
    }
}

public class C {
    public void 門口拿報紙(String 報紙){
        System.out.println("看新發(fā)地菜價?。?);
    }
}
  • 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)在非?;鸬腞xJava都是觀察者模式的實現(xiàn),有興趣的可以看看源碼,OK就到這里了,歡迎指正。

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

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

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