【问题标题】:Should I use Observer Pattern if the subscribers are known in advance? [closed]如果提前知道订阅者,我应该使用观察者模式吗? [关闭]
【发布时间】:2017-09-17 12:33:18
【问题描述】:

当我在 C# 中使用 Unity 时,我遇到了这个问题。但我认为,对于任何 OOP 语言,对于开始学习设计 OOP 结构以及何时使用观察者模式或发布者-订阅者模式的人来说,这个问题通常都会出现。我具体说的eventthe event and delegates in C#

我正在寻找有关使用事件的建议。我感觉event,或者观察者模式非常有用,以至于我害怕过度使用它。我搜索了这个问题,发现社区建议observer patterns is good to use to receive tweeter feedsI should use the Observer Pattern if and only if using the pattern will reduce coupling。在when design patterns should be avoided上进行了讨论,建议优先关注the SOLID principle。有些人列出了使用观察者模式时需要注意的事项,其中常见的有:chains of observersmemory leaks

讨论似乎表明,当事件的订阅者列表预计在运行时发生变化时,使用观察者模式通常是好的。例如,RSS feeds 在任何给定时间都会有不同的订阅者,程序员无法知道谁在接收它。所以是的,在这里使用观察者模式似乎是一个最佳选择。

但是,我似乎仍然不相信我是否应该赞成使用这种模式,如果开发人员在编译时就知道订阅者列表我想进行单元测试

假设在我的游戏中我的角色正在进入一个新区域。进入新区域后,我希望游戏:

效果列表

  1. 在屏幕中间显示一个显示 The Swamp of the Code Smell 的 GUI
  2. 更新任务板以显示特定于该区域的任务
  3. 开始降低我角色的每秒 5 点生命值,因为该区域有难闻的气味,并增加 10 点 MP,因为在那里感觉很好

为了实现这一点,我不相信哪种方式是更好的设计模式:

方法 1:将所有信息输入构造函数以进行单元测试

MapEnter 类在其构造函数中有UIGlobalDamageCharacter、...以及所有必需的类。然后它可以调用GlobalDamage.ApplyDamagePerSecond(myCharacter), UI.ShowText(), ...

我之所以这么想是因为a talk about Unit Test 建议类必须是隔离的,这意味着类不能new 任何其他对象,这只能通过其构造函数获得可交互类的列表来实现。

但是,有关如何对观察者模式进行单元测试的帖子建议我可以进行测试以确保 (1) 事件得到良好订阅和取消订阅,以及 (2) 每个要订阅的方法都能独立运行。所以我不太确定这一点。

另一方面,我似乎也相信,当一个类包含其所有引用作为其构造函数中的类变量时,仅通过查看类变量就更容易理解类在多大程度上负责。

现在,当我想扩展MapEnter 的效果时,问题就来了。假设除了我最初计划的三个效果之外,我现在想为其添加一个新功能:

效果列表:

  1. 开始播放该地区的 BGM

那么现在,我需要更改MapEnter 类的构造函数以了解BgmPlayer。在OnMapEnter() 上更改其实现。更改单元测试用例。以此类推。

这可能会启用Unit Test,但与其他类有很强的联系,因此它似乎具有高耦合度。

方法 2:发布者-订阅者模式

这种方法的一大优点是现在可以非常容易地将任何新想法添加到MapEnter。就像添加代码行以向事件添加/删除方法一样简单。 MapEnter 现在不必担心在其构造函数中使用 N 个参数。

我在这里应用了观察者模式,即使我确切地知道谁将在编译时收听这个事件,这意味着我确实可以在不使用观察者模式的情况下实现这一点。

我的担忧是:

  1. 这会减少耦合吗?在这种情况下使用观察者模式好不好?
  2. 方法 1 中的单元测试参数是否证明方法 1 的合理性?
  3. 如果一个类都引用了它需要调用的内容,就像方法 1 中一样,是否更容易理解代码结构?如果我团队中的其他程序员默默地为MapEnter 的事件添加了新订阅者,如果不查看所有事件的引用,我怎么知道呢? 或者当出现问题时,我是否应该为我的应用程序中的每个事件都这样做?

如果我有理由在这里使用观察者模式,因为它减少了耦合,那么实际上所有方法都可以而且应该通过事件调用其他方法,只要听众不关心谁首先被调用并且没有观察者链。那么这种模式会无处不在,听着看代码even if I ensure there is only 1 or 2 levels of observer chains会很痛苦。

提前致谢。

【问题讨论】:

    标签: c# unit-testing oop unity3d design-patterns


    【解决方案1】:

    决定取决于您的情况,我认为了解观察者和发布者/订阅者模式之间的差异很重要。

    Observer 主要以同步方式实现,当某些事件发生时,observable 调用其所有观察者的适当方法。发布者/订阅者模式大多以异步方式(通过消息队列)实现。

    在观察者/可观察者模式中,观察者知道可观察者。而在发布者/订阅者中,发布者和订阅者不需要相互了解。他们只是在消息队列的帮助下进行通信。

    【讨论】:

    • 感谢您指出两种模式之间的区别。但是,我更担心将所有信息提供给构造函数的参数是否合理,这将使以后在恕我直言中添加功能变得更加困难。你说“决定取决于你的情况”。您能否进一步详细说明在这种特定情况下最好的方法是什么,为什么?我似乎缺乏经验来确定我应该关心哪些因素以及它们将如何影响我的决定。
    • @Matthias,我不知道观察者的实现在你的情况下是什么样的,但是如果你检查参考实现(design-patterns-stories.com/patterns/Observer),我认为不需要“注入”构造函数中的参数。观察者可以附加/分离到主题。另一方面,我不知道您是否需要同步或异步响应才能在观察者和发布者/订阅者之间做出决定
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-09
    • 2019-02-07
    相关资源
    最近更新 更多