Language agnostic 何时使用模板方法与策略?
模板方法模式和策略模式的作用大致相同。我理解它们之间的基本区别(模板方法是基于继承的,策略是基于组合的),但是在什么时候选择一种方法而不是另一种方法时,有什么好的指导方针吗?看起来它们基本上做了相同的事情。OO设计的核心原则之一是“支持组合而不是继承”,因此建议支持策略模式。这显然取决于您在特定场景中试图完成的任务。策略允许在多个位置使用可重用的算法。如果您有一个算法可以由您的消费者提供,并且可以在多个地方使用,那么这是一个很好的策略点(排序算法、谓词、比较器……就是很好的例子) 模板方法专门针对这样的情况:您希望人们能够从类继承,并希望他们能够以可控的方式重写您的实现(基本上防止他们替换所有管道并为他们提供一个特定的扩展点而不会出现问题,因为他们没有调用基本方法或在错误的时间调用它) 它们可以是相似的,也可以用于相同的目的,这取决于你实际上在做什么。Language agnostic 何时使用模板方法与策略?,language-agnostic,design-patterns,Language Agnostic,Design Patterns,模板方法模式和策略模式的作用大致相同。我理解它们之间的基本区别(模板方法是基于继承的,策略是基于组合的),但是在什么时候选择一种方法而不是另一种方法时,有什么好的指导方针吗?看起来它们基本上做了相同的事情。OO设计的核心原则之一是“支持组合而不是继承”,因此建议支持策略模式。这显然取决于您在特定场景中试图完成的任务。策略允许在多个位置使用可重用的算法。如果您有一个算法可以由您的消费者提供,并且可以在多个地方使用,那么这是一个很好的策略点(排序算法、谓词、比较器……就是很好的例子) 模板方法专门针
与所有设计模式一样,很难回答这样的问题,因为没有确切的答案。事实上,在上下文中更容易决定…您可以创建大继承树来更改N个行为中的一个。您可以创建第二个大继承树来更改N个行为中的第二个 但是,您也可以通过创建小型策略树来卸载您的树
因此,如果您注意到添加越来越多的类只是为了在某些行为中添加一些更改,那么是时候为您的类提供策略了。在以下情况下考虑使用策略:
- 您的对象行为需要在运行时更改
- 根据其他条件,您已经具有类层次结构
- 您希望在不同的类之间共享策略逻辑
在其他情况下,应该使用模板模式。当算法需要了解其运行对象的内部时,我使用模板方法 在所有其他情况下(即,当算法只需要使用对象的接口时),我尝试使用策略
此外,只有在有实际算法需要实现时,该策略才有用:如果类之间的唯一区别是(例如)返回什么简单值,则使用模板方法。这两种方法实际上可以非常有效地结合使用 不要把模式看作是有特定代码来实现它们的配方 设计意图是关键,可以有很多实现。通过在代码中的某个地方提到模式名称,您在编写代码时让读者了解了您的意图。实现是次要的 模板方法为您提供一个“具有可替换步骤的算法”。(该算法通常在不可重写的方法中定义(例如final或private)) 这个概念的GoF实现使用继承和方法重写来替换这些步骤 然而,如果这些步骤被策略所取代,您仍然使用模板方法 例如,考虑一个类,该类希望按顺序遍历二叉树,并在每个节点上“做点什么” 这样做的目的是,inoorder()方法是一个模板方法——遍历的结构总是相同的
“hook”方法,即“做某事”的部分,可以在同一个类中实现为方法(并在子类中重写以改变行为),或者在外部实现,在这种情况下,它是“做某事”的策略。我同意Scott的解释 Templatepattern=关注绘制操作执行的一般路线-模板化-基本上是一种“具有可替换步骤的算法”(精心设计),其中可替换步骤可以使用策略模式概念委派 Strategypattern=只关心将客户机与操作的底层实现分离,该操作的结果需要始终遵守一些预定规则(例如排序,其中结果始终是一个排序列表,但您可以将反实际排序定义为冒泡排序或快速排序)
干杯。我不同意以下说法: “模板方法专门针对您需要的情况 人们希望能够继承您的类,并希望他们能够 以受控方式覆盖您的实现。”
如果你想让人们从你的类继承,那么你需要的是一个特定的实现,而不是一个特定的行为。这对我来说很糟糕 一个合理的要求是能够覆盖或提供算法各个步骤的实现。这一目标可以通过模板方法(我们可以有选择地覆盖受保护的方法)或策略模式(我们注入实现)来实现 如果您正在构建一个实现算法的类,并且您希望允许其他开发人员修改该算法中的步骤,这就是您的要求。您唯一的决定是允许他们通过继承还是组合来实现 在所有其他条件相同的情况下,我们应该支持组合而不是继承,但我们甚至应该先弄清楚我们的目标是什么(我们可能两者都不需要)来决定继承/组合
我绝不会从“我想让它们从这个类继承”开始。这是本末倒置。我几乎总是选择策略,因为客户端代码没有依赖性
/**
* 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);