使用策略模式和命令模式
两种设计模式都封装了算法并将实现细节与其调用类解耦。我能看出的唯一区别是策略模式接受执行参数,而命令模式则不接受。
在我看来,命令模式要求在创建它时所有执行信息都可用,并且它能够延迟其调用(可能作为脚本的一部分)。
哪些决定指导是否使用一种模式或另一种模式?
Both design patterns encapsulate an algorithm and decouple implementation details from their calling classes. The only difference I can discern is that the Strategy pattern takes in parameters for execution, while the Command pattern doesn't.
It seems to me that the command pattern requires all information for execution to be available when it is created, and it is able to delay its calling (perhaps as part of a script).
What determinations guide whether to use one pattern or the other?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我提供了几个 GoF 设计模式的封装层次结构表,以帮助解释这两种模式之间的差异。希望它能更好地说明每个封装的内容,以便我的解释更有意义。
首先,层次结构列出了给定模式的适用范围,或者用于封装某些细节级别的适当模式,具体取决于您从表的哪一侧开始。
从表中可以看出,策略模式对象隐藏了算法实现的细节,因此使用不同的策略对象将以不同的方式执行相同的功能。每个策略对象可能针对特定因素进行优化或针对某些其他参数进行操作;并且,通过使用通用接口,上下文可以安全地使用其中任何一个。
命令模式封装的细节级别比算法小得多。它对向对象发送消息所需的详细信息进行编码:接收者、选择器和参数。将流程执行的一小部分具体化的好处是,可以以通用方式在不同的时间点或位置调用此类消息,而无需对其细节进行硬编码。它允许消息被调用一次或多次,或者传递到系统的不同部分或多个系统,而不需要在执行之前知道特定调用的细节。
正如设计模式的典型情况一样,它们并不要求所有实现在细节上都相同才能具有模式名称。细节在实现以及对象中编码的数据与方法参数中编码的数据方面可能有所不同。
I'm including an encapsulation hierarchy table of several of the GoF design patterns to help explain the differences between these two patterns. Hopefully it better illustrates what each encapsulates so my explanation makes more sense.
First off, the hierarchy lists the scope for which a given pattern is applicable, or the appropriate pattern to use to encapsulate some level of detail, depending on which side of the table you start at.
As you can see from the table, a Strategy Pattern object hides details of an algorithm's implementation, so the use of a different strategy object will perform the same functionality but in a different way. Each strategy object might be optimized for a particular factor or operate on some other parameter; and, through the use of a common interface, the context can safely work with either.
The Command Pattern encapsulates a much smaller level of detail than an algorithm. It encodes the details needed to send a message to an object: receiver, selector and arguments. The benefit to objectifying such a tiny part of the process execution is that such messages can be invoked along different points of time or location in a general way without having to hard-code its details. It allows messages to be invoked one or more times, or passed along to different parts of the system or multiple systems without requiring the details of a specific invocation to be known before execution.
As is typical for design patterns, they do not require all implementations to be identical in detail to bear the pattern name. Details can vary in implementation and in what data is encoded in the object versus as method arguments.
策略封装了算法。命令将请求的发送者与接收者分开,它们将请求转换为对象。
如果它是一种算法,那么如何完成某些事情,请使用策略。如果需要将方法的调用与其执行分开,请使用命令。当您对消息进行排队以供以后使用时(例如任务或事务),通常会使用命令。
Strategies encapsulate algorithms. Commands separate the sender from the receiver of a request, they turn a request into an object.
If it's an algorithm, how something will be done, use a Strategy. If you need to separate the call of a method from its execution use a Command. Commands are often used when you queue up messages for later use, like a task or a transaction.
回答一个很老的问题。 (有人看到最新的答案而不是投票最多的答案吗?)
由于相似之处,这是一个有效的混淆。策略模式和命令模式都利用封装。但这并不能使它们相同。
关键区别在于理解封装的内容。两种模式所依赖的面向对象原则是封装变化的。
就策略而言,不同的是算法。例如,一个策略对象知道如何输出到 XML 文件,而另一个策略对象知道如何输出到 JSON。不同的算法被保存(封装)在不同的类中。就是这么简单。
在命令的情况下,变化的是请求本身。请求可能来自
文件菜单>删除
或右键单击>上下文菜单>删除
或只需按下删除按钮
。这三种情况都可以生成3个相同类型的命令对象。这些命令对象仅代表3个删除请求;不是删除算法。由于请求现在是一堆对象,我们可以轻松管理它们。突然之间,提供撤消或重做等功能变得微不足道。命令如何实现请求的逻辑并不重要。在调用execute()时,它可能会实现一个算法来触发删除,或者甚至可以将其委托给其他对象,甚至可能委托给策略。它只是命令模式的实现细节。这就是为什么它被命名为命令,尽管它不是一种礼貌的请求方式:--)
将其与策略进行对比;此模式仅涉及实际执行的逻辑。如果我们这样做,它有助于用最少的类集实现不同的行为组合,从而防止类爆炸。
我认为,Command 帮助我们拓宽对封装的理解,而 Strategy 提供了封装和多态性的自然使用。
Answering a very old question. (is anybody seeing lastest answers instead of most voted?)
It is a valid confusion to have because of the similarities. Both Strategy and Command patterns utilize encapsulation. But that does not make them same.
The key difference is to understand what is encapsulated. The OO principle, both patterns depend on, is Encapsulate what varies.
In case of strategy, what varies is algorithm. For example, one strategy object knows how to output to XML file, while the other outputs to, say, JSON. Different algorithms are kept (encapsulated) in different classes. It is as simple as that.
In case of command, what varies is the request itself. Request may come from
File Menu > Delete
orRight Click > Context Menu > Delete
orJust Delete Button pressed
. All three cases can generate 3 command objects of same type. These command objects only represent 3 requests for deletion; not deletion algorithm. Since requests are bunch of objects now, we could manage them easily. Suddenly it become trivial to provide functionality such as undo or redo.It doesn't matter how command implements the requested logic. On calling execute(), it may implement an algorithm to trigger deletion or it can even delegate it to other objects, may even delegate to a strategy. It is only implementation detail of the command pattern. This is why it is named as command though it is not a polite way to request :--)
Contrast it with strategy; this pattern is only concerned with the actual logic that gets executed. If we do that, it helps to achieve different combinations of behaviors with minimal set of classes, thus preventing class explosion.
I think, Command helps us to broaden our understanding of encapsulation while Strategy provides natural use of encapsulation and polymorphism.
我的看法是,你有多种方法来做同一件事,每一种都是一种策略,运行时的某些东西决定执行哪个策略。
也许首先尝试 StrategyOne,如果结果不够好,请尝试 StrategyTwo...
命令绑定到需要发生的不同事情,例如 TryToWalkAcrossTheRoomCommand。每当某个对象尝试穿过房间时,就会触发此命令,但在其中,它可能会尝试 StrategyOne 和 StrategyTwo 来尝试穿过房间。
标记
The way that I look at it is that you have multiple ways of doing the same thing, each of those is a strategy, and something at runtime determines which strategy gets executed.
Maybe first try StrategyOne, if the results aren't good enough, try StrategyTwo...
Commands are bound to distinct things that need to happen like TryToWalkAcrossTheRoomCommand. This command will be fired whenever some object should try to walk across the room, but inside it, it might try StrategyOne and StrategyTwo for trying to walk across the room.
Mark
我的观点可能是错误的,但我将 命令 视为要执行的函数,或者反应。至少应该有两名玩家:请求该操作的玩家和执行该操作的玩家。 GUI 是命令模式的典型示例:
该命令通常局限于某个范围或业务领域,但不是必需的:您可能有一些命令可以发出账单、启动火箭或删除实现相同接口的文件(例如单个
execute()
方法) )在一个应用程序中。通常命令是自包含的,因此它们不需要执行器提供任何内容来处理它们打算执行的任务(所有必要的信息在构造时给出),有时命令是上下文相关的并且应该能够发现此上下文(Backspace 命令应该知道文本中的插入符位置,以正确删除前一个字符;Rollback 命令应该发现当前事务以回滚;...)。策略有点不同:它更受某些区域的约束。该策略可以定义一个规则来格式化日期(以 UTC?特定于区域设置?)(“日期格式化程序”策略)或计算几何图形的平方(“平方计算器”策略)。从这个意义上说,策略是蝇量对象,它以某些内容作为输入(“日期”、“数字”……)并根据其做出一些决定。也许不是最好的,但很好的策略示例是与 javax.xml.transform.Source 接口连接的策略:取决于传递的对象是 DOMSource 还是 SAXSource 或
StreamSource
策略(在本例中= XSLT 转换器)将应用不同的规则来处理它。实现可以是一个简单的开关
,也可以涉及责任链模式。但这两种模式之间确实有一些共同点:命令和策略将算法封装在同一语义区域内。
I might be wrong in my opinion, but I treat the command as function-to-execute, or reaction. There should be at least two players: the one who requests the action, and the one who executes the action. GUI is typical example for command pattern:
The command is usually bounded to some scope or business area, but not necessary: you may have commands that issue a bill, start a rocket or remove a file implementing the same interface (e.g. single
execute()
method) within one application. Often commands are self-containing, so they don't need anything from the executor to process the task they are intend to (all necessary information is given at construction time), sometimes commands are context-sensitive and should be able to discover this context (Backspace command should know the caret position in the text to correctly remove the previous character; Rollback command should discover the current transaction to rollback; ...).The strategy is a bit different: it is more bound to some area. The strategy may define a rule to format a date (in UTC? locale specific?) ("date formatter" strategy) or to calculate a square for a geometric figure ("square calculator" strategy). Strategies are in this sense flyweight objects, that take something as input ("date", "figure", ...) and make some decision on its basis. Perhaps not the best, but good example of strategy is one connected with
javax.xml.transform.Source
interface: depending on whether the passed object isDOMSource
orSAXSource
orStreamSource
the strategy (= XSLT transformer in this case) will apply different rules to process it. The implementation can be a simpleswitch
or involve Chain of responsibility pattern.But indeed there is something in common between these two patterns: commands and strategies encapsulate algorithms within the same semantic area.
Command:
命令模式为 Command 构建一个框架,它将调用操作的对象与知道如何执行该操作的对象分离
工作流程:
客户端调用调用者 => Invoker 调用 ConcreteCommand => ConcreteCommand调用Receiver方法,该方法实现了抽象Command方法。
优点:客户端不会受到命令和接收器中的更改的影响。调用者在客户端和接收者之间提供松散耦合。您可以使用同一个 Invoker 运行多个命令。
命令模式允许您使用相同的调用者在不同的接收器上执行命令。调用者不知道接收者的类型,
您可以使用命令模式来
java.lang.Thread
是Command模式的一个很好的实现。您可以将Thread视为调用者和调用者。类将 Runnable 实现为 ConcreteCommonad/Receiver,并将run()
方法实现为 Command。策略:
策略模式非常容易理解。 时,请使用此模式
当您有一个算法的多个实现并且算法的实现可以在运行时根据特定条件进行更改
。以航空公司预订系统的票价组件为例,
航空公司希望在不同时间段(高峰月和非高峰月)提供不同的票价。在非高峰旅行日,它希望通过提供有吸引力的折扣来刺激需求。
策略模式的关键要点:
带有代码示例的相关文章:
使用命令设计模式
策略模式的现实示例
Command:
Command pattern build a framework for Command , which decouples the object that invokes the operation from the one that knows how to perform it
Workflow:
Client calls Invoker => Invoker calls ConcreteCommand => ConcreteCommand calls Receiver method, which implements abstract Command method.
Advantage : Client is not impacted changes in Command and Receiver. Invoker provide loose coupling between Client and Receiver. You can run multiple commands with same Invoker.
Command pattern allows you to execute a command on different Receivers by using same Invoker. Invoker is unaware of type of Receiver
You can use Command pattern to
java.lang.Thread
is one good implementation of Command pattern. You can treat Thread as invoker & class implementing Runnable as ConcreteCommonad/Receiver andrun()
method as Command.Strategy:
Strategy pattern is very simple to understand. Use this pattern when
You have multiple implementations for an algorithm and implementation of algorithm can change at run time depending on particular conditions.
Take an example of Airline booking system's Fare component
Airlines would like to offer different Fares during different time periods - Peak and Off Peak months. During Off peak travel days, it would like to stimulate the demand by offering attractive discounts.
Key takeaways of Strategy pattern:
Related posts with code examples:
Using Command Design pattern
Real World Example of the Strategy Pattern
对我来说,区别在于意图之一。两种模式的实现非常相似,但具有不同的目的:
对于策略,使用该对象的组件知道该对象做什么(并将使用它来执行自己的一部分)工作),但它不关心如何它是如何做到的。
对于命令,使用该对象的组件既不知道该命令做什么,也不知道它如何执行它 - 它只知道如何调用它。调用者的任务只是运行命令 - 命令执行的处理并不构成调用者核心工作的一部分。
这就是区别 - 使用组件的对象实际上知道或关心组件的功能吗?大多数时候,这可以根据模式对象是否向其调用者返回值来确定。如果调用者关心模式对象的作用,那么它可能希望它返回一些东西,并且它将是一个策略。如果它不关心任何返回值,那么它可能是一个命令(注意,像 Java Callable 这样的东西仍然是一个命令,因为虽然它返回一个值,但调用者并不关心该值 - 它只是将其传递回来到最初提供该命令的任何内容)。
For me, the difference is one of intent. The implementations of both patterns are pretty similar, but have different purposes:
For a Strategy, the component using the object knows what the object does (and will use it to perform a part of its own work), but it doesn't care how it does it.
For a Command, the component using the object knows neither what the Command does nor how it does it - it just knows how to invoke it. The caller's task is just to run the command - the processing carried out by the Command doesn't form part of the caller's core work.
This is the difference - does the object using the component actually know or care about what the component does? Most of the time this can be determined based on whether the pattern object returns a value to its invoker. If the invoker cares about what the pattern object does then it will probably want it to return something and it will be a Strategy. If it doesn't care about any return value it is probably a Command (note, something like a Java Callable is still a Command because, although it returns a value, the caller doesn't care about the value - it just passes it back to whatever originally supplied the Command).