观察者设计模式 - 具体主题和观察者

9

我阅读的关于观察者设计模式的参考资料 (GOF设计模式、Head First设计模式、http://www.dofactory.com/Patterns/PatternObserver.aspx) 都指出具体主题应该持有对具体观察者的引用。就像这样:

class ConcreteObserver : IObserver
{
    ConcreteSubject concreteSubjectInstance;
    //other code, etc.
} 

现在,如果具体的主题本身实现了一个主题接口(或者继承自某个抽象主题类),为什么不让ConcreteObserver中的类型成为该抽象/接口呢?即:
class ConcreteObserver : IObserver
{
    ISubject concreteSubjectInstance;
    //other code, etc.
} 

此外,为什么不将其作为(例如)IObserver接口中的一个字段呢?最终,鉴于该模式似乎放松了Subject与其Observers之间的耦合,为什么在将Observer与其subject耦合时似乎并未得到推广?

enter image description here

但是真的是这样吗?我只是基于我所读到的例子进行推断。

5个回答

7
根据您的图片,您的“update()”方法没有接收到有关Subject状态的任何信息,因此,如果观察者需要有关此状态的信息(通常在观察者模式中),则它必须从ConcreteSubject检索这些信息调用“GetState()”方法(ISubject中不存在)。
与此方案的另一种选择是,将状态(或整个ConcreteSubject的引用)作为“update()”方法的参数传递。 拥有对ConcreteSubject的引用而不是ISubject的其他常见解释是您可能想要与ConcreteSubject交互以调用业务逻辑(当然不会暴露在ISubject接口中)。

作为参数传递给更新方法:我猜它也可以作为观察者构造函数的参数。 - James Wiseman
是的,要设置内部引用,应该在构造函数中完成。但是如果您不维护内部引用,仍然可以在每个“update()”调用中接收。这是Java内置的观察者模式实现的方式。 - Mr.Eddart

2

仅仅因为你读到的定义中写着subject holds a reference to the concrete observer并不意味着你必须按照字面意思理解。

只要主题有一个指向观察者的引用/链接,无论是具体的还是通过接口/类实现的,该语句仍然成立。

在IObserver和IObservable两侧都看到接口非常普遍。我认为你将会发现的问题是,当你把主题变成抽象时,你需要努力找到如何使状态通用的方法。


1

具体观察者和具体主题的实现也有状态。当主题的状态改变时,具体观察者的状态也会更新。但有时,您可能需要查看您没有的主题状态,为此,最好引用该主题。换句话说,为了查看具体主题的状态。


1

我将尝试提供我的观点。

为什么要使用具体类?不会导致主题和观察者之间的耦合吗?

  • 观察者模式的主要关注点是1对N模型,而不是N对N模型,这是通过Observer接口实现的。

  • 是的,它会导致耦合,并且这是有意的,因此每个具体观察者都将得到他想要的内容,而不需要冗余的“上下文传递”。

耦合是不好的,但原则>解耦。

如果通过Subject接口访问具体主题,我们可以在运行时订阅不同的主题!对吗?

  • 不,对于每个具体观察者的update(),它应该只做一件事情单一责任原则
  • 如果有人想要监听多个事件怎么办?这可以通过组合来完成,而不是将所有东西都堆积在一个update()中。

一些书籍/在线资源的作者将update()转换成像update(subject, context, varName, ...)这样的形式,然后他们假设观察者需要什么,但是观察者需要什么并不是主题关心的事情,为什么不自己处理呢?将具体观察者与具体主题耦合,以便主题只需要发送通知而不是数据。
主题:大家好,我的商店开张了! 观察者A:好的,我想要那个iPhone。 观察者B:好的,我想要那台Windows电脑。 观察者C:我喜欢iPhone和Windows电脑,也许我应该向A、B询问一下。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接