【问题标题】:Why do we need a "receiver" class in the Command design pattern为什么我们在命令设计模式中需要一个“接收器”类
【发布时间】:2013-05-09 19:32:00
【问题描述】:

我正在学习命令设计模式。据我所知,与命令模式相关的四个术语是命令、接收者、调用者和客户端。

具体的命令类有一个execute() 方法,调用者有几个命令。调用者决定何时调用命令的execute() 方法。

execute()方法被调用时,它调用了接收者的一个方法。然后,接收者完成工作。

我不明白为什么我们需要接收器类?我们可以在execute()方法里面做,看来receiver类是多余的。

提前致谢。

【问题讨论】:

    标签: oop design-patterns


    【解决方案1】:

    设计模式用于解决软件问题。

    在尝试理解解决方案之前,您必须先理解问题(在本例中为命令模式)

    命令模式应用的问题是在对象 A(客户端)调用对象 B(接收器)中的方法的上下文中,因此接收器是问题的一部分,而不是解决方案的一部分。

    命令模式提供的解决方案或想法是将A到B的方法调用封装在一个对象(Command)中,实际上这接近于正式的模式定义。当您将请求作为对象进行管理时,您可以解决一些问题或实现一些功能。 (您还需要其他部件,例如 Invoker)

    这个list可以给你一些很好的例子,说明什么样的问题或特性适合命令模式。

    注意:comamnd 模式不需要解耦,实际上最常见的示例模式实现,客户端需要创建一个新的接收器实例,所以我们不能在这里讨论解耦。

    【讨论】:

    • JUnit中使用的命令模式,在这种情况下没有接收者。我们总是把我们的测试代码放在具体的命令类中。
    • 我见过一个老式的实现方式叫做EJBCommand,你可以在其中看到你提到的Command类中的业务逻辑,但是在这种情况下,逻辑在服务器端执行,所以Receiver 是(根据我的解释)执行命令中分配的逻辑的服务器组件。可能你的场景与此相似。
    • 除了客户端=/=调用者,所以它是关于解耦调用者和接收者。
    【解决方案2】:

    想象一个可以做几件事的类,比如 Duck,它可以吃东西和嘎嘎叫。在这个例子中,Duck 是一个接收器。要在此处应用命令模式,您需要能够将吃和呱呱打包成一个命令。它们应该是从带有execute() 方法的Command 基类派生的独立类,因为Duck 只能有一个execute() 方法。所以EatCommand.execute() 调用Duck.eat()QuackCommand.execute() 调用Duck.quack()

    【讨论】:

    • 很好的答案安迪,正是我想要的。
    • 为什么不直接调用duck.eat()而不是通过命令调用呢?
    • @AmitKumarGupta:出于各种应用程序特定的原因。例如,您想在另一个线程中调用duck.eat() 和其他方法。你可以有一个命令队列,从一个线程填充它并在另一个线程中执行。不同的方法可以采用不同数量的参数,这些参数是通过调用线程提供的并存储在命令中,然后在执行线程时,你有一个很好的命令列表,你需要做的就是一一调用它们的Execute
    • 在我见过的所有例子中,一个命令除了调用接收者的方法之外什么都不做。没有传递额外的参数。 Invoker 负责如何以及何时调用它,无论它是队列还是其他线程。所以我不理解命令的需要。
    • 如果 'receiver' 只是一个模型,假设它为一个 github 存储库建模并保存所有元数据,并构建一个命令堆栈,如创建、删除、添加 webhook 等。对我来说在命令中包含创建或删除存储库的逻辑并为命令提供模型而不是将所有这些功能添加到存储库对象中会更有意义。
    【解决方案3】:

    命令模式的目标是将调用者与接收者分离。

    接收者必须完成工作,而不是命令本身,命令只知道要调用的接收者方法是什么,或者命令可以执行其他命令。使用命令模式,调用者不知道该命令的期望是什么。

    因此,一个命令可以被许多调用者重用,以在接收者上执行相同的操作。

    【讨论】:

    • JUnit中使用的命令模式,在这种情况下没有接收者。我们总是将测试代码放在具体的命令类中。
    • 好吧,我不知道 junit 是如何编码的,所以我没有答案。我只是告诉你命令模式的定义是什么,以及在这种情况下接收器是什么。跨度>
    【解决方案4】:

    简短的答案取决于。这不仅仅基于我的观点。来自 GOF,命令模式,实现(第 238 页)

    “一个命令应该有多智能?一个命令可以具有广泛的能力。在一个极端,它只是定义了接收者和执行请求的动作之间的绑定。在另一个极端,它自己实现了一切,而无需完全委托给接收者。当您要定义独立于现有类的命令时,当不存在合适的接收者时,或者当命令隐式知道其接收者时,后一种极端很有用。例如,创建另一个应用程序窗口的命令可能与任何其他对象一样能够创建窗口。”

    所以我认为不应该仅仅为了它而创建一个接收器类,或者因为大多数示例都是这样说的。只有在真正需要时才创建它。一种这样的情况是,充当接收者的类已经作为单独的类存在。如果您必须编写将要被调用/执行的代码并且没有理由为此创建一个单独的类,那么我认为将调用程序代码添加到 Command 本身没有任何错误。

    【讨论】: