使用策略模式和命令模式

Ext*_*kun 118 encapsulation design-patterns strategy-pattern command-pattern

两种设计模式都封装了算法,并将实现细节与其调用类分离.我能辨别的唯一区别是策略模式接受执行参数,而命令模式则没有.

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

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

Hup*_*tes 91

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

首先,层次结构列出了给定模式适用的范围,或者用于封装某些细节级别的适当模式,具体取决于您从哪个表开始.

设计模式封装层次表

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

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

对于设计模式而言,它们通常不要求所有实现在细节上都具有相同的模式名称.细节可以在实现中以及在对象中编码的数据与方法参数之间变化.

  • @KTF,不.Command模式使用一个对象,该对象具有大多数(如果不是全部)所需的信息(例如,接收器,选择器,参数)来调用对象的方法.它是一种简单的模式,可用于其他设计模式,如责任链,集合和您描述的管道模式.您的代表提供的"各种合同"是另一种模式,即Interface. (4认同)

Pau*_*bel 48

策略封装了算法.命令将发送方与请求的接收方分开,它们将请求转换为对象.

如果是算法,将如何完成某项任务,请使用策略.如果需要将方法的调用与其执行分开,请使用命令.排队消息供以后使用时,通常会使用命令,如任务或事务.


rpa*_*abi 25

回答一个非常古老的问题.(有人看到最新的答案,而不是大多数人投票?)

由于相似之处,这是一个有效的混淆.策略和命令模式都使用封装.但这并不能使它们相同.

关键的区别是要了解什么是封装.两种模式依赖的OO原则是封装变化的内容.

在策略的情况下,不同的是算法.例如,一个策略对象知道如何输出到XML文件,而另一个策略对象输出到JSON.不同的算法保存(封装)在不同的类中.它是如此简单.

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

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

将其与战略进行对比; 这种模式只关注执行的实际逻辑.如果我们这样做,它有助于用最少的类集实现不同的行为组合,从而防止类爆炸.

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


MSt*_*odd 15

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

也许首先尝试使用StrategyOne,如果结果不够好,请尝试使用StrategyTwo ...

命令绑定到需要发生的不同事情,如TryToWalkAcrossTheRoomCommand.每当某个对象试图穿过房间时,该命令将被触发,但在其中,它可能会尝试使用StrategyOne和StrategyTwo来试图穿过房间.

标记

  • RE:"做同样事情的多种方式" - 这似乎与战略的一些常见例子相冲突.特别是那些有加法,减法,乘法等实现类的人.也许那些不是很好的例子? (2认同)

dma*_*a_k 7

在我看来,我可能是错的,但我将命令视为执行功能或反应.应该至少有两个参与者:请求操作的人和执行操作的人.GUI是命令模式的典型示例:

  • 应用程序工具栏上的所有按钮都与某些操作相关联
  • 在这种情况下,Button是执行者.
  • 在这种情况下,Action是命令.

该命令通常限制在某个范围或业务范围内,但不是必需的:您可能拥有execute()在一个应用程序中发出帐单,启动火箭或删除实现相同接口(例如单个方法)的文件的命令.通常命令是自包含的,因此它们不需要执行程序中的任何内容来处理它们打算执行的任务(所有必要的信息都是在构造时给出的),有时命令是上下文敏感的并且应该能够发现这种上下文(Backspace命令应该知道文本中的插入符位置以正确删除前一个字符; Rollback命令应该发现要回滚的当前事务; ...).

战略是一个有点不同:它更绑定到其他区域.策略可以定义规则来格式化日期(以UTC?区域设置特定?)("日期格式化程序"策略)或计算几何图形的平方("方形计算器"策略).从这个意义上说,策略是轻量级对象,它将某些东西作为输入("日期","数字",......)并在其基础上做出一些决定.也许不是最好的,但良好的战略的例子是一个具有连接javax.xml.transform.Source接口:根据传递的对象是否是DOMSourceSAXSourceStreamSource策略(=在这种情况下,XSLT转换器)将适用不同的规则来处理它.实施可以是简单的switch或涉及责任链模式.

但实际上这两种模式之间存在共同点:命令和策略将算法封装在同一语义区域内.


Rav*_*abu 5

命令:

基本组件:

  1. 命令为抽象命令声明了一个接口,例如execute()
  2. 接收者知道如何执行特定命令
  3. Invoker持有ConcreteCommand,它必须被执行
  4. 客户端创建ConcreteCommand并分配Receiver
  5. ConcreteCommand定义了CommandReceiver之间的绑定

工作流程:

客户端调用Invoker => Invoker调用ConcreteCommand => ConcreteCommand调用Receiver方法,该方法实现抽象的Command方法。

优点:客户端不受命令和接收器更改的影响。Invoker 在 Client 和 Receiver 之间提供松散耦合。您可以使用同一个 Invoker 运行多个命令。

命令模式允许您使用相同的Invoker在不同的接收器上执行命令。调用者不知道接收者的类型

为了更好地理解概念,看看这个JournalDev文章潘卡·库马尔和dzone文章詹姆斯Sugrue除了维基百科的链接。

您可以使用命令模式来

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

  2. 实现回调机制

  3. 实现撤销和重做功能

  4. 维护命令的历史记录

java.lang.Thread命令模式的一种很好的实现。您可以将Thread视为调用者和类,将Runnable视为ConcreteCommonad/Receiver并将run()方法视为Command

可以在Theodore Norvell 的 文章中阅读命令模式的撤消/重做版本

战略:

策略模式很容易理解。使用此模式时

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

航空公司预订系统的票价组件为例

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

策略模式的关键要点:

  1. 这是一种行为模式
  2. 它基于委托
  3. 它通过修改方法行为来改变对象的内脏
  4. 它用于在算法族之间切换
  5. 它在运行时改变对象的行为

带有代码示例的相关帖子:

使用命令设计模式

策略模式的真实世界示例