1. 程式人生 > >觀察者模式(Java)

觀察者模式(Java)

觀察者模式也稱釋出者模式,它是一種在專案中經常使用的模式。

一.觀察者模式的現實場景

盧康很喜歡玩微信,他喜歡瀏覽朋友圈來了解朋友圈裡面的人的最近情況,以及把自己周邊發生的事情分享給其他人看。今天早上在他上班的路上發生了一件事情,有個老人倒在地上,旁邊的行人紛紛繞開老人離開,沒有一個人主動扶起老人。盧康把這個場景拍了下來,上傳到朋友圈,剛上傳上去就有人回覆了。習偉回覆說:現在老人到底誰敢扶啊,你上去扶老人就被訛上了,到時候你都說不清楚。蔡良說:盧康你怎麼只拍照而不去扶老人啊,我們社會需要多一些正能量,少一些冷漠狀態。 上面場景中,盧康在微信上髮狀態,然後朋友給他回覆資訊狀態,這樣的場景類似於設計模式中的觀察者模式。這裡盧康的朋友的觀察者,而盧康是被觀察者,只要盧康的朋友圈有什麼訊息,觀察者就能知道。 這也類似我java的介面回撥,進行監聽後,就能在觸發的時候收到對應的監聽內容。

二.觀察者模式(Observer Pattern)的定義

定義物件間一種一對多的依賴關係,使得每當一個物件改變狀態,所有依賴於它的物件都會得到通知並被自動更新。

三.觀察者模式的類圖

1

四.觀察者模式的四個角色

1. 抽象主題(Subject)角色

該角色又稱為“被觀察者”,可以增加和刪除觀察者物件。

2.抽象觀察者(Observer)角色

該角色為所有的具體觀察者定義一個介面,在得到主題的通知時更新自己。

3.具體主題(Concrete Subject)角色

該角色又稱為“具體被觀察者”,他將有關狀態存入具體觀察者物件,在具體主題的內部狀態改變時,給所有登記過的觀察者發出通知。

4. 具體觀察者(Concrete Observer)角色

該角色實現抽象觀察者所要求的更新介面,以便使自身的狀態與主題的狀態相協調。

五.觀察者模式的優缺點

觀察者模式中的優點

1.觀察者和被觀察者之間是抽象耦合。被觀察者並不全部知道所有的具體觀察者,他只知道它們有一個共同的介面。比如現實場景中,盧康知道自己的朋友圈資訊被看到,並不知道所有看他資訊的人。

2. 觀察者模式支援廣播通訊。

觀察者模式的缺點

1.如果一個主題有過個直接或間接的觀察者,則通知所有的觀察者會花費很多的時間,而且它的開發和除錯都比較複雜。

2.如果在主題之間有迴圈依賴的華,被觀察者會觸發它們進行迴圈呼叫,導致系統崩潰。

3.如果對觀察者的通知是通過另外的執行緒進行非同步投遞的話,系統必須保證投遞的順序執行。

4.觀察者模式沒有提供相應的機制使觀察者知道所觀察的物件是怎麼發生變化的,只知道結果變化了。

六.觀察者模式的注意事項

觀察者模式使用注意的事項:

1. 廣播鏈問題。一個觀察者既可以有雙重身份,它既可以是觀察者,也可以是被觀察者,邏輯複雜的時候,可維護性就比較低了。所以一般一個觀察者模式中最多出現一個雙重身份的物件就夠了,較易控制。

2.非同步處理的問題。非同步處理就要考慮執行緒安全和佇列的問題。

七.觀察者模式的示例

這裡使用上面的現實場景做程式碼示例。

示例的類圖

2

示例的程式碼

1.抽象主題類,朋友圈ITalkSubject

package p19_observer;

/**
 * 抽象主題,朋友圈
 */
public interface ITalkSubject {

    //讓某些人看見我的朋友圈
    void registerObserver(ITalkObserver observer);

    //不然某些人看見我的朋友圈
    void deleteObserver(ITalkObserver observer);

    //重新整理,讓朋友知道
    void notifyObserver();

}

2.抽象觀察者ITalkObserver

package p19_observer;

/**
 * 抽象觀察者,看朋友圈的人
 */
public interface ITalkObserver {
    //更新朋友圈
    void updateTalk(String msg);
}

3.具體朋友圈ConcreteTalkSubject

package p19_observer;

import java.util.ArrayList;
import java.util.List;

/**
 * 具體的朋友圈
 */
public class ConcreteTalkSubject implements ITalkSubject {

    //觀察者集合,管理那些人能看我的朋友圈
    private List<ITalkObserver> observerList = new ArrayList<>();

    //朋友圈訊息
    private String msg;

    //增加可以看我朋友圈的人
    @Override
    public void registerObserver(ITalkObserver observer) {
        observerList.add(observer);
    }

    //刪除可以看我朋友圈的人
    @Override
    public void deleteObserver(ITalkObserver observer) {
        observerList.remove(observer);
    }

    //重新整理,讓看我朋友圈的人都知道:我更新資訊了
    @Override
    public void notifyObserver() {
        for (int i = 0; i < observerList.size(); i++) {
            observerList.get(i).updateTalk(msg);//給每一個觀察者重新整理一下
        }
    }

    //設定朋友圈資訊
    public void setMessage(String msg) {
        this.msg = msg;
        notifyObserver();//重新整理
    }

}

4.具體觀察者,看朋友圈的人ConcreteTalkObserver

package p19_observer;

/**
 * 具體的看朋友圈的人
 */
public class ConcreteTalkObserver implements ITalkObserver {

    //姓名
    private String name;

    //構造方法,傳入姓名
    public ConcreteTalkObserver(String name){
        this.name=name;
    }

    //關注的朋友圈,資料更新了
    @Override
    public void updateTalk(String msg) {
        System.out.println(name+" 收到一條朋友圈的更新:"+msg);
    }
}

5.測試類TalkDemo

package p19_observer;

/**
 * 測試類
 */
public class TalkDemo {

    public static void main(String[] arg) {
        //建立一個朋友圈
        ConcreteTalkSubject talkSubject = new ConcreteTalkSubject();

        //看朋友圈的人
        ITalkObserver talk1 = new ConcreteTalkObserver("習大");
        ITalkObserver talk2 = new ConcreteTalkObserver("蔡亮");

        //把看朋友圈的人新增到朋友圈中
        talkSubject.registerObserver(talk1);
        talkSubject.registerObserver(talk2);

        //新增朋友圈資訊,別人就可以看到
        talkSubject.setMessage("今天看到一個老大爺摔倒在地上,沒有人去扶老大爺!");

    }

}

程式執行結果;

3

--------------------- 本文來自 崢嶸life 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/wenzhi20102321/article/details/80330335?utm_source=copy