使用策略模式和命令模式
这两种devise模式都封装了一个algorithm,并将实现细节从其调用类中分离出来。 唯一的区别是我可以看出,战略模式需要参数执行,而命令模式不。
在我看来,命令模式要求创build时所有的执行信息都是可用的,并且能够延迟其调用(可能作为脚本的一部分)。
什么决定指导是否使用一种模式或另一种模式?
我包含了几个GoFdevise模式的封装层次表,以帮助解释这两种模式之间的差异。 希望能更好地说明每个封装的内容,所以我的解释更有意义。
首先,层次结构列出了给定模式适用的范围,或者根据您开始的表的哪一侧,使用合适的模式来封装一些细节层次。
从表中可以看出,策略模式对象隐藏了algorithm实现的细节,因此使用不同的策略对象将以不同的方式执行相同的function。 每个策略对象可能会针对特定的因素进行优化,或者对其他参数进行操作; 并通过使用通用接口,上下文可以安全地与任何一个工作。
命令模式比algorithm封装了更小的细节级别。 它编码发送消息到对象所需的细节:接收器,select器和参数。 客观化stream程执行的这一小部分的好处是可以在不同的时间点或位置以一般的方式调用这样的消息,而不必对其细节进行硬编码。 它允许消息被调用一次或多次,或者传递到系统或多个系统的不同部分,而不需要在执行之前知道具体调用的细节。
正如典型的devise模式一样,它们并不要求所有的实现细节都是相同的,以承载模式名称。 细节可以在实现中以及在对象中编码哪些数据与作为方法参数而变化。
战略封装algorithm。 命令将发送者与请求的接收者分开,他们将请求转变为对象。
如果它是一个algorithm,将如何做,使用一个策略。 如果您需要将方法的调用与其执行分离,请使用Command。 当您将消息排队以备后用时,通常使用命令,如任务或事务。
回答一个非常古老的问题。 (有人看到最新的答案,而不是最多的投票?)
由于相似性,这是一个有效的混淆。 战略和命令模式都使用封装 。 但是这并不能使它们一样。
关键的区别是理解封装的内容。 OO原则,两种模式都依赖于封装的变化 。
在策略的情况下, algorithm是不同的。 例如,一个策略对象知道如何输出到XML文件,而另一个输出到JSON。 不同的algorithm被保存( 封装 )在不同的类中。 它是如此简单。
在命令的情况下, 请求本身有所不同。 请求可能来自File Menu > Delete
或Right Click > Context Menu > Delete
或Just Delete Button pressed
。 这三种情况都可以生成3个相同types的命令对象。 这些命令对象只代表3个删除请求; 不是删除algorithm。 由于请求现在是一堆对象,我们可以轻松pipe理它们。 突然间,提供撤销或重做等function变得微不足道。
命令如何实现请求的逻辑并不重要。 在调用execute()时,它可以实现一个触发删除的algorithm,甚至可以委托给其他对象,甚至可以委托给一个策略。 这只是命令模式的实现细节。 这就是为什么它被命名为命令,虽然它不是一个礼貌的方式来请求 : – )
与战略相对照; 这种模式只关心被执行的实际逻辑 。 如果我们这样做,有助于以最less的一组类来实现不同的行为组合,从而防止类爆炸。
我认为,Command帮助我们扩大了对封装的理解,而Strategy提供了封装和多态的自然使用。
我所看到的方式是,你有多种方式来做同样的事情,每一种都是一种策略,并且在运行时决定哪一种策略被执行。
也许首先尝试StrategyOne,如果结果不够好,试试StrategyTwo …
命令被绑定到需要发生的事情,如TryToWalkAcrossTheRoomCommand。 只要某个物体应该穿过房间,这个命令就会被触发,但是在里面,它可能会尝试使用StrategyOne和StrategyTwo来尝试走过房间。
标记
我认为我可能是错的,但是我把这个命令当作函数执行或反应。 应该至less有两个参与者:请求行动的人和执行行动的人。 GUI是命令模式的典型例子:
- 应用程序工具栏上的所有button都与某个操作关联。
- button是这种情况下的执行者。
- 行动是在这种情况下的命令。
该命令通常与某个范围或业务范围有关,但并非必要:在一个应用程序中,您可能有命令发出账单,启动火箭或移除实现相同接口的文件(例如,单个execute()
方法)。 通常命令是自包含的,所以执行者不需要任何东西来处理他们打算的任务(所有必要的信息都是在施工时给出的),有时命令是上下文敏感的,应该能够发现这个上下文( Backspace命令应该知道文本中的插入符号位置以正确删除以前的字符; 回滚命令应该发现当前要回滚的事务;)。
这个策略有点不同:它更多地局限于某个领域。 该策略可能会定义一个规则来格式化date(以UTC?locale特定?)(“date格式化程序”策略)或计算几何graphics的平方(“平方计算器”策略)。 在这个意义上说,策略就是轻量级对象,它把某些东西当作input(“date”,“graphics”),并在其基础上作出一些决定。 也许不是最好的,但是策略的一个很好的例子是与javax.xml.transform.Source
接口相关联的一个:取决于传入的对象是DOMSource
还是SAXSource
或StreamSource
,策略(在这种情况下= XSLT转换器)将应用不同的规则处理它。 实施可以是一个简单的switch
或涉及责任链模式 。
但是这两种模式确实有一些共同之处:命令和策略将algorithm封装在相同的语义区域内。
命令:
基本组件:
- Command为
execute()
这样的抽象命令声明了一个接口, - 接收者知道如何执行一个特定的命令
- Invoker拥有必须执行的ConcreteCommand
- 客户端创buildConcreteCommand并分配Receiver
- ConcreteCommand定义了Command和Receiver之间的绑定
工作stream程:
客户端调用Invoker => Invoker调用ConcreteCommand => ConcreteCommand调用Receiver方法,该方法实现抽象Command方法。
优点 :客户端不会影响Command和Receiver的更改。 调用者在客户端和接收者之间提供松耦合。 您可以使用相同的Invoker运行多个命令。
命令模式允许您使用相同的Invoker在不同的接收器上执行命令。 调用者不知道接收者的types
为了更好地理解概念,请查看Pankaj Kumar的这篇JournalDev 文章和James Sugrue的 dzone 文章以及Wikipedia链接。
您可以使用命令模式
-
解耦命令的调用者和接收者
-
实现callback机制
-
实现撤销和重做function
-
保持命令的历史
java.lang.Thread
是Command模式的一个很好的实现。 你可以把Thread作为调用者和类实现Runnable作为ConcreteCommonad / Receiver和run()
方法作为Command 。
在Theodore Norvell的 文章中可以阅读Undo / Redo版本的命令模式
战略:
战略模式很容易理解。 使用此模式时
对于algorithm,您有多个实现,algorithm的实现可以在运行时根据特定条件进行更改 。
以航空公司预订系统的票价组件为例
航空公司希望在不同的时间段提供不同的票价 – 高峰和非高峰月份。 在非高峰期的旅行日,它想通过提供有吸引力的折扣刺激需求。
战略模式的关键要点:
- 这是一种行为模式
- 这是基于代表团
- 它通过修改方法行为来改变对象的内容
- 它用于在algorithm族之间切换
- 它在运行时改变对象的行为
与代码示例相关的post:
使用命令devise模式
战略格局的现实世界范例
对我来说,差异是一个意图。 这两种模式的实现非常相似,但有不同的目的:
-
对于策略,使用对象的组件知道对象的作用(并将使用它来执行自己的工作的一部分),但它不关心它是如何做的。
-
对于一个命令,使用该对象的组件不知道该命令做了 什么 ,也不知道它是如何做的 – 它只知道如何调用它。 调用者的任务只是运行命令 – 由命令执行的处理不构成调用者的核心工作的一部分。
这是不同的 – 使用组件的对象是否真的知道或关心组件的function? 大多数情况下,这可以根据模式对象是否将值返回给调用者来确定。 如果调用者关心模式对象的作用,那么它可能会希望它返回一些东西,这将是一个策略。 如果它不关心任何返回值,它可能是一个Command(注意,像Java Callable这样的东西仍然是一个Command,因为虽然它返回一个值,但是调用者并不关心这个值 – 它只是把它传回去到最初提供命令的任何东西)。