我和某人就策略模式的真正含义进行了一场极客争论,我需要一位专家来解决这个问题。
我们都同意,策略模式允许在运行时更换类的内部结构(例如,行为),同时保持相同的接口。 然而,她的论点是“为了让[算法]成为一种策略,你必须得到相同的结果”。 我的观点是,交换“算法”或类的逻辑可能意味着重写操作的结果不同,但它仍然满足策略模式的目的、意图(和分类)。
她的代码示例带有注释:
根据您的定义,类的任何子类都将是一种策略。 它们具有相同的方法定义(签名),因此可以互换。
Interface Strategy
{
DoArithmatic(int[] a)
}
Class A : Strategy
public int DoArithmatic(int[]a)
{
int temp = 0;
for(int i =0; i< a.length; i++)
temp += a[i]
}
Class B : Strategy
public int DoArithmaticB(int[]a)
{
int temp = 0;
for(int i =a.length -1; i>-1; i--)
temp += a[i]
}
Class C : Strategy
public int DoArithmatic(int[]a)
{
int temp = 0;
for(int i =0; i< a.length; i++)
temp -= a;
}
int[] a = { 1,2,3 }
ClassA.DoArithmatic(a) = 6
ClassB.DoArithmatic(a) = 6
ClassC.DoArithmatic(a) = -6//This one is not interchangeable
前两个是策略。 因为对于任何输入,他们都会给你完全相同的答案。 最后一个不是。 仅仅因为它给了你一个 int 并不意味着它是一个策略。 他们必须“做”同样的事情。
您不能仅仅使用“更高”的抽象术语来使它们成为一种策略。
这些都做“数学”,但它们并不都以不同的方式做“相同”的事情。 这就是战略的本质。
那么,谁是对的呢?
I had a geek fight with someone over what the strategy pattern really is and I need a expert to settle the matter.
We both agree that the strategy pattern allows for the guts of a class (e.g., the behavior) to be swapped out at runtime while maintaining the same interface. However, her contention is that "For [the algorithms] to be a strategy, You would have to get the same results". My contention is that swapping an "algorithm" or logic of a class could mean that the results of the overridden operation are different, but that it still meets the purpose, intent (and classification) of the strategy pattern.
Her code example with comments:
By your definition, any subclasses of a class would be a strategy. They have the same method definitions (signatures), and are therefore interchangeable.
Interface Strategy
{
DoArithmatic(int[] a)
}
Class A : Strategy
public int DoArithmatic(int[]a)
{
int temp = 0;
for(int i =0; i< a.length; i++)
temp += a[i]
}
Class B : Strategy
public int DoArithmaticB(int[]a)
{
int temp = 0;
for(int i =a.length -1; i>-1; i--)
temp += a[i]
}
Class C : Strategy
public int DoArithmatic(int[]a)
{
int temp = 0;
for(int i =0; i< a.length; i++)
temp -= a;
}
int[] a = { 1,2,3 }
ClassA.DoArithmatic(a) = 6
ClassB.DoArithmatic(a) = 6
ClassC.DoArithmatic(a) = -6//This one is not interchangeable
The first two are strategies. Because for any input they will give you the EXACT same answer. the last one is not. Just because it gives you an int does not make it a strategy. They have to "DO" the same thing.
You can't use a "higher" abstraction term just to make them a strategy.
These all do "MATH" but they are not all doing the "same" thing in a different way. That is the essence of a strategy.
So, who's right?
发布评论
评论(9)
先生,您是对的,您的同事需要阅读 GoF。
“策略模式让算法独立于使用它们的客户端而变化。”
请参阅:
http://www.dofactory.com/Patterns/PatternStrategy.aspx
You sir are correct and your coworker needs to read the GoF.
"The strategy pattern lets the algorithms vary independently from clients that use them."
See:
http://www.dofactory.com/Patterns/PatternStrategy.aspx
从技术上讲,策略可以为所欲为。
只有当“外部上下文”规定了一些无法在编程接口中捕获的固定且可重复的行为(称为“所需属性”)时,您才需要注意您的策略确实可以像 Liskov 那样可替代这些理想的特性。
Technically, strategies can do whatever they want.
It is only when the "outer context" dictates some fixed and repeatable behaviour that cannot be captured in the programmatical interface (call them "desirable properties"), that you need to take care that your strategies are truly substitutable à la Liskov with respect to these desirable properties.
我支持你的意见。 只要可以在相同的上下文中使用不同的策略,它们就可以做非常不同的事情。
例如,如果您想访问树中的每个节点,有效的策略可能是:
所有策略都会以不同的顺序访问节点,但目标 (访问每个节点)将是相同的。 因此,如果顺序不重要,则任一策略都适合您的需求。
I support your opinion. Different strategies can do very different things as long as they can be used in the same context.
For example, if you want to visit each node in a tree, valid strategies could be:
All strategies would visit the nodes in a different order, yet the objective (visiting each node) would be the same. So if the order does not matter, either strategy fits your needs.
FWIW,维基百科文章同意您的观点,但从未听说过她的立场。
FWIW, the Wikipedia article agrees with you and has never heard of her position.
他们必须做同样的事情,但这并不意味着他们给出完全相同的结果。 GoF 的激励示例是不同的布局算法或不同的寄存器分配算法之一。 这些策略具有相同的目标 - 在页面上布局文本和图像块,或者将虚拟寄存器分配给硬件寄存器 - 但它们不必创建完全相同的结果。
因此,如果示例中
策略
的目标是对输入进行任何算术运算,那么每个示例都是实现该目标的策略。 如果目标是对传递的数组求和,则DoArithmatic
将被调用CalculateSum
,最终的示例将无法符合策略的约定,因此违反LSP。They have to do the same thing, but that doesn't mean they give the exact same result. The motivating example from the GoF is one of different layout algorithms, or different register allocation algorithms. The strategies have the same goal - layout blocks of text and images on a page, or assigning virtual registers to hardware registers - but they don't have to create exactly the same result.
So if the goal of the
Strategy
in your example is to do any arithmetic with the input, then each example is a strategy for that goal. If the goal was to sum the array it is passed,DoArithmatic
would have been calledCalculateSum
, and the final example would fail to conform to the contract of the strategy, and so violate LSP.根据“Head First设计模式”(参见此处)第 24 页
“策略模式定义了一系列算法,
封装每一个,并使它们可以互换。
策略让算法独立于
使用它的客户。 “
所以先生,你是对的,至少根据定义该模式的人来说是这样,但他们知道什么。
According to "Head first Design Patterns" (see here) page 24
"The Strategy Pattern defines a family of algorithms,
encapsulates each one, and makes them interchangeable.
Strategy lets the algorithm vary independently from
clients that use it. "
so sir you are correct, at least according to the people who defined the pattern, but what do they know.
你是。 该策略的重点是替代算法。 它们是否提供相同的结果是期望行为的副产品。
You are. The point of the strategy is to substitute the algorithm. Whether they deliver the same result is a by-product of the desired behavior.
我认为更正确的说法是,策略是否必须确定性相同的问题超出了策略模式定义的范围。
如果一个函数对于给定的输入总是返回相同的结果,那么它是确定性的。 如果两个函数是确定性的,并且对于相同的输入它们总是返回相同的值,那么它们是确定性等价的。 它们可能有也可能没有相同的副作用; 如果他们这样做,那么他们只是简单的等价物。
通常情况并非如此。 让我们考虑一个似乎需要确定性等价的示例:排序。 您可能会认为,如果两个比较器实现对于相同的输入无法返回相同的结果,那么至少其中一个一定有错误,但情况不一定如此。
排序顺序因国家/地区而异。 有些地方不区分重音进行排序。 有些人把麦克老鸭和麦克老鸭放在一起,等等。 这些是策略,这是策略模式的完美应用,并且这些策略肯定不是确定性等价的。
你赢了。
I think it would be more correct to say that the question of whether the strategies must be deterministically identical is outside the scope of the definition of the strategy pattern.
If a function always returns the same result for given inputs, it is deterministic. If two functions are deterministic and they always return the same value for the same inputs then they are deterministically equivalent. They may or may not have the same side effects; if they do then they are just plain equivalent.
Typically this is not the case. Let us consider an example that appears to require deterministic equivalence: sorting. You might think that if two comparer implementations fail to return the same result for the same inputs then at least one of them must be faulty, but this is not necessarily the case.
Sort orders vary between countries. Some places sort accent-insensitively. Some put McDuck with MacDuck, and so forth. These are strategies, this is a perfect application of strategy pattern, and the strategies are most certainly not deterministically equivalent.
You win.
我也不得不同意。 定价计算器策略就是一个很好的例子。 您可以采用不同的策略来计算发票的最终金额,具体取决于商品数量、客户类型、运输目的地等多个变量。这些策略中的每一个肯定会返回不同的结果,并且仍然会被考虑策略模式。
I also have to agree. A good example would be a pricing calculator strategy. You could have different strategies for calculating the final amount of an invoice depending on several variables like quantity of items, type of customer, shipping destination, etc. Each of those strategies would definitely be expected to return a different result and it would still be considered a Strategy pattern.