【发布时间】:2010-10-14 21:33:51
【问题描述】:
模板方法模式和策略模式做的事情大致相同。我了解它们之间的基本区别(模板方法是基于继承的,策略是基于组合的),但是对于何时选择一个而不是另一个有什么体面的指导吗?看起来他们做的事情基本上是一样的。
【问题讨论】:
标签: language-agnostic design-patterns
模板方法模式和策略模式做的事情大致相同。我了解它们之间的基本区别(模板方法是基于继承的,策略是基于组合的),但是对于何时选择一个而不是另一个有什么体面的指导吗?看起来他们做的事情基本上是一样的。
【问题讨论】:
标签: language-agnostic design-patterns
策略允许在多个地方使用可重用的算法。如果您有一个算法可以由您的消费者提供并且可以在多个地方使用,那么这是 Strategy 的好地方(排序算法、谓词、比较器......就是很好的例子)。
模板方法专门针对您希望人们能够从您的类继承并希望他们能够以受控方式覆盖您的实现的情况(基本上防止他们替换您的所有管道并为他们提供特定的扩展点而不会有问题,因为他们没有调用基方法或在错误的时间调用它)。
它们可以是相似的,并且它们可以用于相同的目的,具体取决于您实际在做什么。 与所有设计模式一样,很难回答这样的问题,因为没有真正确定的答案。实际上,根据上下文来决定更容易......
【讨论】:
这两者实际上可以非常有效地结合使用。
不要将模式视为具有特定代码来实现它们的配方。
设计意图是关键,可以有多种实现方式。通过在代码中某处提及模式名称,您可以让读者了解您在编写该代码时的意图。实施是次要的。
模板方法为您提供“具有可替换步骤的算法”。 (算法通常定义在不可覆盖的方法中(例如 final 或 private))
此概念的 GoF 实现使用继承和方法覆盖来替换这些步骤。
然而,如果这些步骤被替换为策略,你仍在使用模板方法。
例如,考虑一个想要按顺序遍历二叉树并在每个节点“做某事”的类。
意图是 inorder() 方法是一个模板方法 - walk 的结构总是相同的。
“钩子”方法,“做某事”的部分可以实现为同一类中的方法(并在子类中重写以改变行为),或者在外部,在这种情况下,它是一种“做某事”的策略.
【讨论】:
当算法需要了解其运行对象的内部结构时,我会使用模板方法。
在所有其他情况下(即当算法只需要使用对象的接口时),我尝试使用策略。
此外,策略仅在需要实现实际算法时才有用:如果类之间的唯一区别是(例如)返回什么简单的值,请使用模板方法。
【讨论】:
在以下情况下考虑使用策略:
在其他情况下,使用模板模式就足够了。
【讨论】:
我不同意这种说法(来自this answer):
"模板方法专门针对你想要的情况 人们能够从您的班级继承并希望他们能够 以受控方式覆盖您的实现。”
如果您希望人们从您的类继承,那么您想要一个特定的实现,而不是想要一个特定的行为。我闻起来很臭。
WANT 的一个有效功能是能够覆盖或提供算法的各个步骤的实现。这个目标可以通过模板方法(我们可以选择性地覆盖受保护的方法)或策略模式(我们注入实现)来实现。
如果您正在构建一个实现算法的类,并且希望允许其他开发人员更改该算法中的步骤,这就是您的要求。您唯一的决定是是否允许他们通过继承或组合来做到这一点。
在所有其他条件相同的情况下,我们应该优先考虑组合而不是继承,但我们甚至应该首先弄清楚我们的目标是什么(我们可能两者都不需要)来决定继承/组合。
我永远不会从“我想让他们从这个类继承”开始。这是国际海事组织本末倒置。
【讨论】:
您可以创建大继承树来更改 N 行为之一。您可以创建第二个大继承树来更改 N 行为中的第二个。
但您也可以通过创建小型策略树来卸载您的树。
因此,如果您注意到添加越来越多的类只是为了对某些行为进行一些更改 - 是时候为您的类提供策略了。
【讨论】:
我同意并同意 Scott 的解释。
模板 pattern = 关心绘制操作将沿其进行的通用线 - 模板 - 基本上是一种“具有可替换步骤的算法”(非常好的创造),其中可以委派可替换步骤使用策略模式概念。
策略模式 = 只关心将客户端与操作的下划线实现脱钩,该操作的结果需要始终遵守某些预定规则(例如排序,结果始终是排序列表,但您可以将实际排序推迟到冒泡排序或快速排序)。
干杯。
【讨论】:
核心 OO 设计原则之一是“优先组合胜于继承”,因此建议优先考虑策略模式。这显然取决于您在特定场景中要完成的工作。
【讨论】:
我的总结:策略模式比模板方法模式耦合更松散,这通常是一件好事。
罗伯特 C.马丁TEMPLATE METHOD & STRATEGY: Inheritance vs. Delegation
因此,STRATEGY 模式比 模板方法模式。而模板方法模式允许 通用算法来操作许多可能的详细信息 实现,通过完全符合 DIP 的 STRATEGY 模式 另外允许每个详细的实现由 许多不同的通用算法。
DIP 是Dependency Inversion Principle:
A.高级模块不应该依赖于低级模块。两者都应该依赖于抽象。 B. 抽象不应该依赖于细节。细节应该取决于抽象。
【讨论】:
我几乎总是会选择策略,因为客户端代码不依赖于实现,而在模板模式中,实现的一部分保留在抽象类中,抽象类中的任何更改都可能需要更改客户端,这很重要导致代码死板,我们最终告诉开发人员“这比我预期的变化更大”。
但如果在抽象类中获取通用代码真的很有帮助,我会毫不犹豫地这样做,并尝试让与客户端代码相关的代码远离它
【讨论】:
我更喜欢混合使用两者,将默认实现(来自模板模式)转储到策略模式的上下文类中。这样,我可以强制用户调用我希望他们调用的方法,以便算法步骤的执行顺序保持可控。
/**
* enables replaceable steps in algorithm
*/
public interface HouseStrategy{
void buildWalls();
void buildPillars();
}
public class HouseContext{
//public API that enforces order of execution
public void build(HouseStrategy strategy){
buildFoundation();//default implementation
strategy.buildPillars();//delegated to concrete strategy
strategy.buildWalls();//delegated to concrete strategy
buildWindows();//default implementation
}
//default implementation
private void buildWindows() {
System.out.println("Building Glass Windows");
}
//default implementation
private void buildFoundation() {
System.out.println("Building foundation with cement,iron rods and sand");
}
}
public class WoodenHouse implements HouseStrategy {
@Override
public void buildWalls() {
System.out.println("Building Wooden Walls");
}
@Override
public void buildPillars() {
System.out.println("Building Pillars with Wood coating");
}
}
public class GlassHouse implements HouseStrategy {
@Override
public void buildWalls() {
System.out.println("Building Wooden Of glass");
}
@Override
public void buildPillars() {
System.out.println("Building Pillars with glass coating");
}
}
正如我们所见,具体策略仍有待扩展。如,
public class GlassHouse implements HouseStrategy,EarthquakeResistantHouseStrategy{......}
用法
HouseContext context = new HouseContext();
WoodenHouse woodenHouseStrategy = new WoodenHouse();
context.build(woodenHouseStrategy);
GlassHouse glassHouseStrategy = new GlassHouse();
context.build(glassHouseStrategy);
我在这里看到的一个缺点是具体策略只能改变算法的变体行为,即 buildWalls() 和 buildPillars()。如果我们需要更改不变部分,即 buildFoundation() 和 buildWindows(),我们需要创建另一个 Context 类来实现新行为。 尽管如此,我们还是得到了一些纯策略模式中没有的代码可重用性:-)
【讨论】: