簡體   English   中英

觀察者模式-觀察者是否需要了解主題?

[英]Observer pattern - does the observer needs to know the Subject ?

我試圖了解觀察者模式,這是我在網上選擇的一個簡單代碼:

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


/**
 * The observer pattern is a software design pattern in which an object, 
 * called the subject, maintains a list of its dependents, called observers, and 
 * notifies them automatically of any state changes, usually by calling one of their methods
 * @author X220
 *
 */


interface Subject 
{
    // methods to register and unregister observers
    public void register(Observer obj);

    public void unregister(Observer obj);

    // method to notify observers of change
    public void notifyObservers();

    // method to get updates from subject
    public Object getUpdate(Observer obj);
}

interface Observer 
{
    // method to update the observer, used by subject
    public void update();

    // attach with subject to observe
    public void setSubject(Subject sub);
}

/**
 * Holds a list of the observers
 * @author X220
 *
 */
class MySubject implements Subject 
{
    private List<Observer> observers;
    private String message;
    private boolean changed;
    private final Object MUTEX = new Object();

    public MySubject() 
    {
        this.observers = new ArrayList<>();
    }

    @Override
    public void register(Observer obj) 
    {
        if (obj == null)
            throw new NullPointerException("Null Observer");
        synchronized (MUTEX) {
            if (!observers.contains(obj))
                observers.add(obj);
        }
    }

    @Override
    public void unregister(Observer obj) 
    {
        synchronized (MUTEX) 
        {
            observers.remove(obj);
        }
    }

    @Override
    public void notifyObservers() 
    {
        List<Observer> observersLocal = null;
        // synchronization is used to make sure any observer registered after
        // message is received is not notified
        synchronized (MUTEX) 
        {
            if (!changed)
            {
                return;
            }
            observersLocal = new ArrayList<>(this.observers);
            this.changed = false;
        }
        for (Observer obj : observersLocal) 
        {
            obj.update();
        }
    }

    @Override
    public Object getUpdate(Observer obj) {
        return this.message;
    }

    // method to post message to the topic
    public void postMessage(String msg) {
        System.out.println("Message Posted to Topic:" + msg);
        this.message = msg;
        this.changed = true;
        notifyObservers();
    }

}

class MyObserver implements Observer 
{
    private String name;
    private Subject topic;

    public MyObserver(String nm) {
        this.name = nm;
    }

    @Override
    public void update() {
        String msg = (String) topic.getUpdate(this);
        if (msg == null) {
            System.out.println(name + ":: No new message");
        } else
            System.out.println(name + ":: Consuming message::" + msg);
    }

    @Override
    public void setSubject(Subject sub) {
        this.topic = sub;
    }

}


public class RunCode1 
{

    public static void main1(String[] args) {
        // create subject
        MySubject topic = new MySubject();

        // create observers
        Observer obj1 = new MyObserver("Obj1");
        Observer obj2 = new MyObserver("Obj2");
        Observer obj3 = new MyObserver("Obj3");

        // register observers to the subject
        topic.register(obj1);
        topic.register(obj2);
        topic.register(obj3);

        // attach observer to subject
        obj1.setSubject(topic);
        obj2.setSubject(topic);
        obj3.setSubject(topic);

        // check if any update is available
        obj1.update();

        // now send message to subject
        topic.postMessage("New Message");
    }
}

我幾乎了解了這個主意,但是有一件事情困擾着我:觀察者有一個setSubject()方法,他本人(觀察者)也注冊了subject並設置了Subject,在我看來這有點不對勁。

我可以更改接口並刪除setSubject()方法,但是我的問題是從Observer模式的角度來看,我真的還需要在注冊后設置一個主題嗎?

沒錯,由於此行,此方法添加了不必要的依賴性:

String msg = (String) topic.getUpdate(this);

可以刪除這兩個方法( setSubjectgetUpdate ),並且可以從update()直接檢索msg ,如下所示:

@Override
public void update(String msg) {
    if (msg == null) {
        System.out.println(name + ":: No new message");
    } else
        System.out.println(name + ":: Consuming message::" + msg);
}

隨着notifyObservers的更新:

for (Observer obj : observersLocal) 
{
    obj.update(this.message);
}

好吧,觀察者必須知道有關他的主題的細節,否則他將無法觀察它,對嗎? 與現實生活相匹配:您還必須了解正在觀察的對象的那些細節,以便在何時需要采取特定措施時知道對不對?

關鍵是, 您可以將其與interfaces分離 ,因此您可以構建一個更通用的觀察者...然后,您所觀察的對象只需要實現該觀察接口,觀察者就可以使用了。

讓我們看看1995年UML中GoF定義的Observer模式:

觀察員

ConcreteObserver有一個鏈接subjectConcreteSubject -模式沒有指定如何設置它; 可以將其注入構造函數中,也可以使用setSubject()方法注入。

Subject方面,您的代碼具有registerunregister ,類似於AttachDetach ,並且notifyObservers適合該模式。

從觀察者模式的角度來看,我真的還需要在注冊后設置主題嗎?

根據此模式的GoF版本, ConcreteObserver必須以某種方式知道主題才能進行自我更新。 因此,您需要設置一個主題。

模式的一種變體(Java的Observer / Observable ),其中Update()方法傳遞一個對象,該對象包含與狀態有關的信息,以便ConcreteObserver可以更新其狀態而不必與ConcreteSubject進行通信。 從理論上講,您然后不需要存儲指向該主題的鏈接。

取決於趨於穩定的事物

模式的目標不是消除所有依賴性。 在軟件開發中,有一種趨勢是希望添加新的觀察者(考慮Microsoft Word的GUI版本有多少)。 主題是傾向於不更改代碼的類。 軟件設計中的一條規則是在不大可能更改其代碼的類創建依賴項 觀察者模式是說ConcreteObservers傾向於改變(隨着時間的推移有新版本),因此我們不想也必須改變ConcreteSubjects

如果您更改主題的代碼,該模式將無濟於事。 例如,讓我們以代表手機電池剩余電量的主題為例,其值的范圍是0到10。 也許當值小於2時,觀察者會顯示紅色圖像。 現在,如果開發人員決定最好顯示0到100的值,因為它具有更多的分辨率來知道電池可持續使用多長時間,則您必須更改所有觀察者的代碼(它們取決於主題)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM