首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >观察者模式-观察者需要知道对象吗?

观察者模式-观察者需要知道对象吗?
EN

Stack Overflow用户
提问于 2015-10-05 13:41:22
回答 3查看 2.2K关注 0票数 0

我正在尝试理解观察者模式,这是我在网上选择的一个简单代码:

代码语言:javascript
复制
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()方法,他自己(观察者)也注册主题并设置主题,这在我看来有点错误。

我可以更改接口并删除setSubject()方法,但是我的问题是,从观察者模式的角度来看,我真的需要在注册后设置一个主题吗?

EN

回答 3

Stack Overflow用户

发布于 2015-10-05 13:51:11

你是对的,这个方法添加了不必要的依赖,因为下面这一行:

代码语言:javascript
复制
String msg = (String) topic.getUpdate(this);

这两个方法(setSubjectgetUpdate)可以删除,msg可以直接从update()中检索,如下所示:

代码语言:javascript
复制
@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中的更新

代码语言:javascript
复制
for (Observer obj : observersLocal) 
{
    obj.update(this.message);
}
票数 2
EN

Stack Overflow用户

发布于 2015-10-05 13:46:15

那么,观察者必须知道关于他的主题的细节,否则他就不能观察到它,对吧?与现实生活相匹配:你还必须了解你正在观察的对象的细节,以便知道何时需要采取特定的行动,对吗?

问题是,你可以用接口来解耦它,这样你就能够构建一个更通用的观察者……然后,您的被观察对象只需要实现该观察者接口,您的观察者就可以开始工作了。

票数 1
EN

Stack Overflow用户

发布于 2015-10-06 22:15:28

让我们看一下1995年以来由UML语言中的GoF定义的观察者模式:

Subject方面,您的代码具有registerunregister,它们类似于AttachDetach,并且您的notifyObservers也符合该模式。

从观察者模式的角度来看,我真的需要在注册后设置一个主题吗?

根据该模式的这个GoF版本,ConcreteObserver必须以某种方式知道主题才能自我更新。所以,你需要设置一个主题。

该模式还有一种变体(Java语言的Observer/Observable),其中Update()方法传递一个包含状态相关信息的对象,这样ConcreteObserver就可以在不必与ConcreteSubject通信的情况下更新其状态。从理论上讲,你不需要存储到主题的链接。

依赖于趋于稳定的事物

该模式的目标不是消除所有依赖项。主题是不会有代码更改的类。软件设计中的一条规则是在代码中不太可能发生更改的类上创建依赖项。

如果您更改了主题的代码,则该模式不起作用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32941942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档