【问题标题】:Can a [GoF]-ConcreteSubject override the notify method?[GoF]-ConcreteSubject 可以覆盖通知方法吗?
【发布时间】:2019-09-15 06:36:17
【问题描述】:

我正在模拟一种情况:

  • NotificationBox:观察者
  • list1list2list3:主题

现在我将使用观察者模式制作一张图表来描述每个列表实现不同类型的 notify() 的事实(例如,列表状态的某些变化只需要通知某个观察者,使用一些标准)

我做了类似的东西:

在这种情况下,每个主体都会重写 notify 方法,以便仅根据某些标准通知观察者的某个子集,并使用正确的更新方法。

示例

ListaMDDpubblico 是由某个文件组成的列表,每个文件都有一个特定的标签。当一个文件被加载时,只有与“喜欢”文件标签的用户相关联的notificationBox才应该使用updateMDD来通知。

它对 [GoF] 友好吗?

或者我需要制作3个不同的Subject抽象类,每个都以列表方式实现notify方法?

提前致谢

[编辑]

经过对答案和评论的一些推理,我对这种情况的另一种可能的设计是:

通过这种方式,每个更改都会通知所有订阅的观察者(针对每种不同类型的主题),并且了解是否必须考虑通知的逻辑在由 notificationBox 实现的更新方法中建模(因此现在的通知是广播和每个 ConcreteSubject 不需要对具体观察者一无所知)。

【问题讨论】:

  • 让设计 GoF 友好的原因是什么?我不是为了制作模式而建模,而是使用模式来建模它们适合的位置。
  • 是的,抱歉,我不解释上下文。是为了考试,需要将两种模式应用于建模的类图。假设问题是通知通知框列表状态更改,是正确使用观察者模式吗?
  • 你不能覆盖notify,因为每个实例都有自己订阅的观察者。
  • 但是通知方法类似于“对于所有观察者都执行:observer.update”,我需要对这样一个事实进行建模,即在每个主题中都有一个不同的观察者子集应该被通知更改根据具体标准,不同的主体需要调用不同的更新方法。见例子。如果我不覆盖通知,我如何对三个主题的不同行为进行建模?
  • 关于您的编辑的问题:1) 除了 PaginaDiCorso 之外还有其他 SubjectPDC 课程是否现实? 2)您的 NotificationBoxObs 是否真的继承自 3 个其他类(多重继承或多个接口的实现)还是相反?

标签: design-patterns uml observer-pattern


【解决方案1】:

观察者与 GoF 模式的比较

在 GoF 观察者中,notify() 在抽象 Subject 中实现:调用所有观察者的 update() 函数,由他们决定对象更新通知是否相关。这样,主体就不必知道观察者的任何具体信息。

第一个潜在的设计问题

如果您让Subject 决定通知哪个Observer,则主题可能需要了解有关观察者的更多详细信息。根据主体需要了解观察者的决策信息,这可能合适,也可能不合适:

  • 如果具体主体需要了解具体观察者,则该设计会以一种不可取的方式增加耦合。事实上,这违背了open/close principle,因为添加新类型的观察者需要调整具体的主题。维修噩梦近在眼前!
  • 如果具体主体只需要知道抽象观察者的接口,你的设计就可以了。尽管如此,本着DRY 的精神,我还是建议将此模式与template method pattern 结合起来,让notify() 具有普遍性,并使其依赖于可以根据具体主题而改变的抽象条件。

第二个潜在的设计问题

您的具体观察者似乎需要知道主题的类型才能调用正确的更新函数。我不确定是否真的如此,但这是您对updateXXX() 命名约定的印象,因为每个XXX 仅用于一个主题。

如果是这种情况,Observer 抽象将取决于Subject 的具体实现。这似乎不是一个好主意:具体类可能依赖于抽象类,但相反是违反开/关原则的。

UML 建模问题

在UML图上,我建议不要使用从SubjectObserver的黑色组合菱形:

  • 复合(黑色菱形)表示观察者完全属于主体(即如果主体被删除,其观察者将无法生存)。我怀疑这里的情况。
  • 聚合(白色菱形)具有相似的含义,但具有共享所有权(非排他性)。我不能排除这一点,但我也没有看到在这里使用它的令人信服的论据。
  • 我会推荐一个简单的(一对多)关联。
  • 如果您将多重性 1 留在主题一侧,则您的观察者必须在其构建过程中进行注册。这是您打算实施的,还是应该是 0..1 ?

从具体观察者到所有具体主题的可导航关联提出了问题:

  • 具体观察者和抽象主体之间是否存在可导航的关联? (在这种情况下,为了准确起见,绘制与抽象类的关联)
  • 或者是否存在 3 个可导航的关联:具体观察者和每个具体主题之间?

考虑这方面的开/关原则。如果您需要添加一个新的具体主题,您希望会发生什么?您是否必须更改所有具体观察者(添加新关联)?还是您希望它在没有任何变化的情况下工作(因为关联与抽象主题有关)?

【讨论】:

  • 我又来了。白色菱形没有语义(参见 UML 2.5 的第 110 页)。不推荐。
  • @qwerty_so 我认为我们同意。在同一页 110 上,据说“有时使用属性来对使用一个实例将一组实例分组在一起的情况进行建模;这称为聚合”。我的观点是,它绝对不是这里的专有所有权。正如我所说,“最好有一个简单的关系”(对于“简单”,我的意思既不是聚合也不是复合,正如你所建议的那样)。然而,我不能排除聚合作为一种可能性,因为一个主题的所有观察者都形成了某种群体。我应该改进我的配方吗?
  • 第 1 页的方框。 110 是明确的:共享聚合的精确语义因应用领域和建模者而异。因此,除非您在领域中描述了确切的语义,否则不应使用它。如果您推荐一个支持聚合的“简单”关联,我会投赞成票。我认为很多这些(错误使用的)聚合源于对旧 UML 规范中“次优”定义的错误解释。
  • 此外,具有多重性的关联就足够了,除非您想通过复合聚合显示明确的生命周期依赖性。
  • @qwerty_so 感谢您对答案的彻底审查。我已经更新了它。让我知道现在是否足够清楚。
【解决方案2】:

GoF 书籍第 298-299 页详细讨论了这个问题。我认为上面显示的设计最接近,

明确指定感兴趣的修改。您可以提高更新效率 通过扩展主题的注册接口以允许注册观察者 仅适用于感兴趣的特定事件。当这样的事件发生时,主体 只通知那些对该事件感兴趣的观察者。

不过,GoF 书的实现方式与上面显示的设计略有不同。上述设计扩展了观察者接口以指定每种类型的事件,因此事件类型的知识传播到每个主题(以及每个观察者,如果有多个)。此外,如果将来添加新的事件类型,则会很容易编辑观察者界面。

出于这些原因,我更喜欢使用多个观察者的方法。与其将所有更新方法组合到一个接口中,不如将它们分成GsObserverMddObserverDdlObserver。每个主题只能注册其中一个观察者接口,但NotificationBox 可以实现所有三个。

【讨论】:

  • 您好,感谢您的回答。好的,所以我应该将更新方法分解为通知框扩展的 3 个抽象类。但是我如何处理通知方法,即使每个主题都有一种类型的观察者,它也需要决定需要通知的观察者的子集,如果我在主题抽象类中实现通知方法,我将无法处理,因为每个受试者使用不同的标准来选择子集。我该怎么办?
  • 好的,我已经编辑了实现您的一些答案的解决方案!它对 [GoF] 更友好?
猜你喜欢
  • 2017-02-08
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多