使用策略模式和命令模式

这两种设计模式都封装了一个算法,并将实现细节与它们的调用类分离。我能看出的唯一区别是,Strategy 模式接受执行的参数,而 Command 模式不接受。

在我看来,命令模式要求在创建时所有执行信息都是可用的,并且它能够延迟调用(可能作为脚本的一部分)。

什么决定指导是使用一种模式还是另一种模式?

40564 次浏览

我的看法是,你有多种方法来做同样的事情,每种方法都是一个策略,在运行时某种东西决定了哪种策略被执行。

也许先试试第一策略,如果结果不够好,试试第二策略..。

命令绑定到需要发生的不同的事情,比如 TryToWalkAcrossTheRoomCommand。当某个对象试图穿过房间时,这个命令将被触发,但是在它内部,它可能会尝试 Strategy One 和 Strategy Two 试图穿过房间。

马克

策略封装算法。命令将请求的发送者和接收者分开,它们将请求转换成对象。

如果这是一个算法,如何做一些事情,使用策略。如果需要将方法的调用与其执行分离,请使用 Command。当您对消息进行排队以供以后使用时(如任务或事务) ,通常会使用命令。

在我看来,我可能是错误的,但是我将 指挥官视为函数到执行或反应。应该至少有两个参与者: 一个请求操作,另一个执行操作。GUI 是命令模式的典型例子:

  • 应用程序工具栏上的所有按钮都与某些操作相关联。
  • 在这种情况下,巴顿是遗嘱执行人。
  • 在这种情况下,操作是命令。

这个命令通常局限于某个范围或业务领域,但不是必需的: 您可能有发出账单、启动火箭或删除在一个应用程序中实现相同接口的文件(例如单个 execute()方法)的命令。命令通常是自包含的,所以它们不需要执行者提供任何东西来处理它们想要完成的任务(所有必要的信息都在构造时给出) ,有时命令是上下文敏感的,应该能够发现这个上下文(退格命令应该知道文本中插入符号的位置,以正确删除前一个字符; Rollback命令应该发现当前要回滚的事务; ...)。

策略有点不同: 它更多地绑定到某些区域。该策略可以定义一个规则来格式化日期(以 UTC?具体地点?)(“日期格式化程序”策略)或为几何图形计算一个正方形(“正方形计算器”策略)。在这个意义上,策略就是轻量级的对象,它将某些东西作为输入(“日期”、“数字”、 ...) ,并根据它们做出一些决定。也许不是最好的,但是策略的一个很好的例子是与 javax.xml.transform.Source接口连接的: 根据传递的对象是 DOMSourceSAXSource还是 StreamSource,策略(在这种情况下是 XSLT 转换器)将应用不同的规则来处理它。该实现可以是一个简单的 switch或涉及 Chain of responsibility pattern

但事实上,这两种模式之间有一些共同之处: 命令和策略将算法封装在同一语义区域内。

我包含了几种 GoF 设计模式的封装层次结构表,以帮助解释这两种模式之间的差异。希望它能更好地说明每个封装的内容,这样我的解释就更有意义了。

首先,层次结构列出了给定模式适用的范围,或者用于封装某种级别的细节的适当模式,这取决于您从表的哪一侧开始。

design pattern encapsulation hierarchy table

从表中可以看到,策略模式对象隐藏了算法实现的细节,因此使用不同的策略对象将以不同的方式执行相同的功能。每个策略对象可以针对特定因素进行优化,或者对其他一些参数进行操作; 并且,通过使用公共接口,上下文可以安全地使用这两者中的任何一个。

命令模式封装了比算法小得多的细节。它对向对象发送消息所需的细节进行编码: 接收器、选择器和参数。对流程执行中如此微小的一部分进行对象化的好处是,可以以通用的方式沿着不同的时间点或位置调用这些消息,而不必对其细节进行硬编码。它允许一次或多次调用消息,或将消息传递到系统的不同部分或多个系统,而无需在执行前知道特定调用的详细信息。

正如典型的设计模式一样,它们并不要求所有实现在细节上完全相同以承载模式名称。实现中的细节以及对象中编码的数据与作为方法参数的数据可能有所不同。

回答一个很老的问题。(有人看到的是最新的答案而不是最多的投票吗?)

这是一个有效的混淆,因为有相似之处。Strategy 和 Command 模式都利用 封装。但这并不意味着他们是一样的。

The key difference is to understand 什么 is encapsulated. The OO principle, both patterns depend on, is Encapsulate what varies.

对于策略,变化的是 算法。例如,一个策略对象知道如何输出到 XML 文件,而另一个策略对象知道如何输出到 JSON。不同的算法(encapsulated)保存在不同的类中。就这么简单。

在命令的情况下,变化的是 请求本身。请求可能来自 File Menu > DeleteRight Click > Context Menu > DeleteJust Delete Button pressed。这三种情况都可以生成3个相同类型的命令对象。这些命令对象只代表3个删除请求; 不代表删除算法。因为现在请求是一堆对象,所以我们可以很容易地管理它们。突然之间,提供撤消或重做之类的功能就变得微不足道了。

Command 如何实现所请求的逻辑并不重要。在调用 execute ()时,它可以实现一个触发删除的算法,甚至可以将其委托给其他对象,甚至可以委托给一个策略。它只是命令模式的实现细节。这就是为什么它被命名为 指挥官,虽然这不是一个礼貌的方式来 请求: ——)

将它与策略进行对比; 这个模式只关心实际执行的 逻辑。如果我们这样做,就可以用最少的类实现不同的行为组合,从而防止类爆炸。

我认为,Command 帮助我们拓宽了对封装的理解,而 Strategy 提供了对封装和多态性的自然使用。

命令:

基本组成部分:

  1. Command 为诸如 execute()之类的抽象命令声明了一个接口
  2. Receiver 知道如何执行特定的命令
  3. Invoker 持有必须执行的 混凝土指挥部
  4. 客户端 创建 混凝土指挥部并分配 < em > 接收器
  5. ConcreteCommand 定义了 命令和 < em > Receiver 之间的绑定

工作流程:

客户端 调用 调用者 = > 调用者调用 混凝土指挥部 = > 混凝土指挥部调用 传承人方法,该方法实现抽象 命令方法。

优势 : 客户端在 Command 和 Receiver 中不受更改的影响。调用程序在客户端和接收方之间提供松散耦合。可以使用同一个 Invoker 运行多个命令。

Command pattern allows you to execute a command on different 接球手 by using same 调用者. Invoker is unaware of type of Receiver

为了更好地理解概念,除了 Wikipedia 链接之外,还可以查看 Pankaj Kumar的 JournalDev article詹姆斯 · 苏格鲁的 dzone 文章

您可以使用 司令部模式来

  1. 解耦调用者和接收者的命令

  2. Implement callback mechanism

  3. 实现撤消和重做功能

  4. 维护命令的历史记录

java.lang.Thread is one good implementation of 命令 pattern. You can treat 线头 as invoker & class implementing 可以跑 as 混凝土共用/接收器 and run() method as 命令.

撤销/重做版本的命令模式可以在 Theodore Norvell's 文章读取

策略:

策略模式非常容易理解

一个算法有多个实现,算法的实现可以在运行时根据特定条件更改。

< em > 机票预订系统的票价组成部分 为例

航空公司希望提供不同的票价在不同的时间段-高峰期和非高峰期的月份。在非高峰期旅游日,它希望通过提供有吸引力的折扣来刺激需求。

策略模式的主要特点:

  1. 这是一种行为模式
  2. 这是基于授权的
  3. It changes guts of the object by modifying method behaviour
  4. It's used to switch between family of algorithms
  5. 它在运行时更改对象的行为

相关文章及代码示例:

使用命令设计模式

战略模式的真实世界范例

对我来说,不同之处在于意图,两种模式的实现非常相似,但有不同的目的:

  • 对于 Strategy,使用对象的组件知道对象所做的 什么(并将使用它来执行自己工作的一部分) ,但是它不关心 怎么做,而是执行它。

  • 对于 Command,使用该对象的组件既不知道 Command 所做的 什么,也不知道它所做的 怎么做——它只知道如何调用它。调用方的任务仅仅是运行命令——由 Command 执行的处理并不构成调用方核心工作的一部分。

这就是区别——使用组件的对象实际上知道或关心组件的作用吗?大多数情况下,这可以根据模式对象是否向其调用者返回值来确定。如果调用程序关心模式对象做什么,那么它可能希望它返回一些东西,它将是一个 Strategy。如果它不关心任何返回值,那么它可能是一个 Command (注意,类似 Java Callable 的东西仍然是一个 Command,因为尽管它返回一个值,调用者并不关心这个值——它只是将它传递回原来提供 Command 的任何东西)。