模板方法模式和策略模式大致相同.我理解它们之间的基本差异(模板方法是基于继承,策略是基于组合),但是有什么体面的指导方针可以选择何时选择其中一个?看起来他们做的基本相同.
策略允许在多个地方使用可重用的算法.如果您的算法可以由您的消费者提供并且可以在多个地方使用,那么这是策略的一个好地方(排序算法,谓词,比较器......就是很好的例子).
模板方法专门针对您希望人们能够从您的类继承并希望他们能够以受控方式覆盖您的实现的情况(基本上阻止他们更换所有管道并为他们提供特定的扩展点冒着问题,因为他们没有调用基本方法或在错误的时间调用它.
它们可以是相似的,它们可以起到同样的作用,取决于你实际在做什么.与所有设计模式一样,很难回答这样的问题,因为没有确切的答案.在上下文中确定更容易...
这两者实际上可以非常有效地一起使用.
不要将模式视为具有特定代码的配方来实现它们.
设计意图是关键,可以有很多实现.通过在某处提到代码中的模式名称,您可以在编写代码时让读者了解您的意图.实施是次要的.
模板方法为您提供"具有可替换步骤的算法".(该算法通常以不可覆盖的方法定义(例如最终或私有))
此概念的GoF实现使用继承和方法覆盖来替换这些步骤.
但是,如果这些步骤被策略替换,您仍然使用Template方法.
例如,考虑一个想要按顺序遍历二叉树并在每个节点"执行某些操作"的类.
目的是inorder()方法是一个模板方法 - walk的结构总是相同的.
"钩子"方法,"做某事"的部分可以作为同一类中的方法实现(并在子类中重写以改变行为),或者在外部,在这种情况下,它是"做某事"的策略.
当算法需要知道它运行的对象的内部时,我使用Template方法.
在所有其他情况下(即当算法只需要使用对象的接口时),我尝试使用策略.
此外,策略仅在有实际算法实现时才有用:如果类之间的唯一区别是(例如)要返回的简单值,请使用Template方法.
在以下情况下考虑使
您的对象行为需要在运行时更改.
您已按其他条件拥有类层次结构.
您希望跨不同的类共享策略逻辑.
在其他情况下,应该使用模板模式.
我不同意这个说法(来自这个答案):
"模板方法专门针对您希望人们能够从您的类继承并希望他们能够以受控方式覆盖您的实现的情况."
如果你想让人们从你的班级继承,那么你就想要一个特定的实现,而不是想要一个特定的行为.那对我来说闻起来很糟糕.
WANT的一个有效之处是能够覆盖或提供算法各个步骤的实现.这个目标可以通过模板方法(我们可以选择性地覆盖受保护的方法)或策略模式(我们注入实现)来实现.
如果您正在构建一个实现算法的类,并且您希望允许其他开发人员更改该算法中的步骤,那么这就是您的要求.您唯一的决定是允许他们通过继承或组合来做到这一点.
在所有其他条件相同的情况下,我们应该支持组合而不是继承,但我们甚至应该首先弄清楚我们的目标是什么(我们可能不需要),从而得到继承/组合决策.
我永远不会从"我想让他们继承这个班级"开始.这是马IMO之前的推车.
您可以创建大继承树只是为了更改N行为之一.并且您可以创建第二个大继承树来更改N行为中的第二个.
但您也可以通过创建小型策略树来卸载树.
因此,如果您注意到添加了越来越多的类只是为了在某些行为中添加一些更改 - 现在是时候为您的类提供策略了.