【问题标题】:Command Pattern seems needlessly complex (what am I failing to understand?)命令模式似乎不必要地复杂(我不明白什么?)
【发布时间】:2011-08-29 04:16:39
【问题描述】:

我已经阅读了命令模式,但我认为我遗漏了一些东西。 Command 对象的存在是为了抽象出 Receiver 对象的细节。在我看来,我们可以简单地停在这里,并持有对 Command 对象的引用以在适当的时间执行适当的方法。

那么,为什么需要调用者?这种额外的间接提供了什么优势?我们已经将 Receiver 的详细信息隐藏在了 Command 后面,那么 Command 对客户端也隐藏起来的动机是什么?

【问题讨论】:

标签: design-patterns abstraction command-pattern information-hiding


【解决方案1】:

如果您传递不同类型的命令,Invoker 很有用。您可以使用相同的 Invoker 来执行不同的具体命令。在不同的节点上,使用 ConcreteCommand 而不是 Invoker 标记 Receiver 允许松散耦合。 Receiver 可以更改方法的名称(例如 switchOn 到 swithcOnTV),如下例所示:

相关帖子:Using Command Design pattern

要了解Invoker 的用途,我希望您将这个article 用于餐厅和汽车服务中心用例。

服务员 (Invoker) 从他的垫子上的Customer 处点菜。然后,Order 将排队等待订单厨师并到达处理它的厨师 (Receiver)。

客户端是Customer。他通过服务员Invoker 将他的请求发送给Receiver。服务员通过将命令(在这种情况下为订单)写在支票上然后放置它来封装命令(在这种情况下为订单),创建 ConcreteCommand 对象,这是命令本身。

Receiver 将是厨师,在完成相关命令之前发送给他的所有订单的工作后,开始工作。

该示例的另一个值得注意的方面是,用于订单的面板不仅支持来自菜单的订单,因此它可以支持烹饪许多不同项目的命令。

【讨论】:

    【解决方案2】:

    好吧,如果你这么说,它看起来很复杂,但通常接收器根本不需要是一个对象。它可以不仅仅是一个被执行的函数(作为一个事件)。此外,调用者不需要是一个类。它只是触发命令的东西。这也可以是按钮中的事件处理程序。

    即使Wikipedia 也总结了几个使用此模式的示例,而实际上不必为调用者和接收者实现完整的单独类。一个示例是向导对话框,其中 GUI 填充命令对象,并且完成按钮触发它。所以那个 GUI 类(无论如何你都有)既是客户端又是调用者。

    【讨论】:

    • 如果同一个对象既是 Client 又是 Invoker,则违背了该模式的目的。请参阅我自己的答案和@MerlynMorgan-Graham 的答案。
    • @jaco0646 部分,当然,但#ItDepends 取决于您的应用程序的其余部分。扩展向导的示例,向导基类可以实现基本步骤,包括调用(针对抽象接口),而后代构造命令。从以表格形式完成所有事情,到将该逻辑提取到命令构建器,这是一个进步。所以我不同意它完全违背了模式的目的。但是,是的,在绿地场景中,您必须更进一步才能充分受益于它的各个方面。
    • 实现基本步骤而将其他步骤推迟到由后代实现的抽象接口的基类是模板方法模式的定义。可以肯定,这是一个有用的模式,但与命令模式完全不同。 Wikipedia 中的向导描述(当前)非常模糊,可以通过任意数量的模式来实现。 (根据我的经验,维基百科一般不擅长设计模式。)
    【解决方案3】:

    据我所知,该模式的全部意义在于拥有某种命令生产者和某种命令消费者,但允许生产者在不改变消费者的情况下创建或修改命令。

    该模式将生产者称为“客户端”,将消费者称为“调用者”。

    这是一个面向对象的回调。

    那么,为什么需要调用者

    据我从all the examples on Wikipedia 得知,调用者没有明确的形式。它只是一些接受抽象命令的代码。

    在我看来,我们可以简单地停在这里,并持有对 Command 对象的引用

    如果调用命令以接受或保持对抽象命令的引用的事物在您的代码中有意义,那么您已经实现了调用程序。

    如果一段代码既是生产者又是消费者,那么命令模式毫无价值。仅当您将抽象命令传递给想要调用它们的对象时才值得。

    【讨论】:

      【解决方案4】:

      我们已经在命令后面隐藏了接收器的详细信息,

      完全正确,但谁在隐藏这些细节,又向谁隐藏? 答案是实例化命令实现的人正在隐藏,而调用命令抽象的人是隐藏的。显然,这两个动作都由一个对象执行是没有意义的,就像你可以对自己隐藏某些东西一样。

      因此,Client 实例化了一个ConcreteCommand 并将其传递给Invoker,后者只知道Command 接口。实际上,客户端为调用者执行依赖注入。

      还请注意,实现 ConcreteCommand 有不同的方法(请参阅 https://stackoverflow.com/a/35617012/1371329)。如果 ConcreteCommand 有某种机制可以动态发现自己的 Receiver,则可能不需要依赖注入。

      【讨论】:

        猜你喜欢
        • 2022-12-11
        • 2020-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-27
        • 1970-01-01
        相关资源
        最近更新 更多