模板方法和策略模式有什么区别?

有人请向我解释模板方法模式和策略模式之间有什么区别?

据我可以告诉他们是99%相同 – 唯一的区别是模板方法模式具有抽象类作为基类,而战略类使用由每个具体战略类实现的接口。

然而,就客户而言,他们的消费方式完全一样 – 这是正确的吗?

两者的主要区别在于具体algorithm的select。

使用Template方法模式时,通过子类化模板在编译时发生。 每个子类通过实现模板的抽象方法提供了一个不同的具体algorithm。 当客户端调用模板的外部接口的方法时,模板根据需要调用其抽象方法(其内部接口)来调用algorithm。

class ConcreteAlgorithm : AbstractTemplate { void DoAlgorithm(int datum) {...} } class AbstractTemplate { void run(int datum) { DoAlgorithm(datum); } virtual void DoAlgorithm() = 0; // abstract } 

相比之下, 策略模式允许在运行时通过遏制来selectalgorithm。 具体algorithm是通过单独的类或函数实现的,这些类或函数作为parameter passing给构造函数或构造方法。 为此参数select哪种algorithm会根据程序的状态或inputdynamic变化。

 class ConcreteAlgorithm : IAlgorithm { void DoAlgorithm(int datum) {...} } class Strategy { Strategy(IAlgorithm algo) {...} void run(int datum) { this->algo.DoAlgorithm(datum); } } 

综上所述:

  • 模板方法模式:通过子类化 编译时间algorithmselect
  • 策略模式:通过遏制 运行时algorithmselect

当一个特定的操作有一些不变的行为时,模板模式被使用,这个行为可以用其他不同的原始行为来定义。 抽象类定义了不变的行为,而实现类定义了依赖的方法。 在一个策略中,行为实现是独立的 – 每个实现类定义了行为,而且它们之间没有共享的代码。 两者都是行为模式,因此,客户也以同样的方式消费。 通常,策略有一个公共方法 – execute()方法,而模板可以定义一组公共方法以及一组子类必须实现的支持私有基本types。

这两种模式可以很容易地一起使用。 您可能有一个策略模式,其中几个实现属于使用模板模式实现的一系列策略。

你可能是指模板方法模式。 你是对的,他们服务非常相似的需求。 我想说,如果你有一个“模板”algorithm已经定义的步骤,其中的子类覆盖这些步骤来改变一些细节的情况下,最好使用模板方法。 在策略的情况下,你需要创build一个接口,而不是inheritance,你正在使用委托。 我认为这是一个更强大的模式,根据DIP依赖倒置原则可能更好。 这是更强大的,因为你清楚地定义了一个新的战略抽象 – 一种做事的方式,这不适用于模板方法。 所以,如果这种抽象是有意义的 – 使用它。 但是,使用模板方法在简单情况下可能会给您更简单的devise,这也很重要。 考虑哪个词更适合:你有模板algorithm吗? 或者在这里关键的是你有一个抽象的策略 – 做一些事情的新方法

模板方法的示例:

 Application.main() { Init(); Run(); Done(); } 

在这里,你从应用程序inheritance,并取代在init,run和done中完成的工作。

策略示例:

 array.sort (IComparer<T> comparer) 

在这里,写一个比较器时,不要从数组inheritance。 数组将比较algorithm委托给比较器。

我认为这两种模式的分类图都显示出不同之处。

战略
在一个类中封装一个algorithm
链接到图像 在这里输入图像说明

模板方法
把algorithm的确切步骤推迟到一个子类
链接到图像 在这里输入图像说明

inheritance与聚合(is-a与has-a)。 实现相同目标有两个途径。

这个问题显示了一些select之间的权衡: inheritance与聚合

两者都非常相似,都以相似的方式被客户端代码所使用。 与上面最stream行的答案不同, 两者都允许在运行时selectalgorithm

两者的不同之处在于, 策略模式允许不同的实现使用完全不同的方式实现期望的结果, 模板方法模式指定了用于实现结果的总体algorithm(“模板”方法) – 留给特定实现(子类)的唯一select是所述模板方法的某些细节。 这是通过使模板方法调用一个或多个被子类覆盖(即实现)的抽象方法来完成的,与模板方法本身不是抽象的并且不被子类覆盖。

客户端代码使用抽象类types的引用/指针调用模板方法,指向可以在运行时确定的具体子类之一的实例,就像使用策略模式一样。

策略与模板方法模式策略与模板方法的区别


相似

策略和模板方法模式在它们之间有很多相似之处。 策略和模板方法模式都可以用来满足开闭原则,使得软件模块在不改变代码的情况下易于扩展。 两种模式都表示通用function与该function的详细实现的分离。 不过,它们所提供的粒度有一些差异。


差异

以下是我在研究这两种模式时所观察到的一些差异:

  1. 在策略中,客户和策略之间的耦合更加松散,而在模板方法中,两个模块耦合得更紧密。
  2. 在策略中,虽然抽象类也可以根据具体情况而使用,但大多使用一个接口,而不使用具体类,而在Template方法中大多使用抽象类或具体类,不使用接口。
  3. 在Strategy模式中,类的整体行为一般用接口表示,另一方面,Template方法用于减less代码重复,样板代码在基本框架或抽象类中定义。 在Template Method中,甚至可以有一个具有默认实现的具体类。
  4. 简而言之,您可以在策略模式中更改整个策略(algorithm),但是在Template模式中,只有一些事情发生变化(algorithm的一部分),而其余事件保持不变。 在Template Method中,不​​变步骤是在一个抽象基类中实现的,而变体步骤要么是默认的实现,要么根本就没有实现。 在Template方法中,组件devise器强制执行algorithm所需的步骤和步骤的sorting,但允许组件客户端扩展或replace某些步骤。

图片来自bitesized博客。

不,他们不一定以相同的方式消耗。 “模板方法”模式是为未来实施者提供“指导”的一种方式。 你告诉他们,“所有Person对象都必须有一个社会安全号码”(这是一个微不足道的例子,但是它正确地实现了这个想法)。

策略模式允许多种可能的实现被切入和切出。 它不是(通常)通过inheritance来实现,而是通过让调用者通过所需的实现来实现。 一个示例可能是允许ShippingCalculator提供几种不同的计算方法之一(可能是NoSalesTax实现和PercentageBasedSalesTax实现)。

所以,有时客户会真正告诉对象使用哪个策略。 如在

 myShippingCalculator.CalculateTaxes(myCaliforniaSalesTaxImpl); 

但客户永远不会为基于模板方法的对象做这件事。 事实上,客户可能不知道一个对象是基于模板方法。 模板方法模式中的那些抽象方法甚至可能受到保护,在这种情况下,客户端甚至不知道它们存在。

我build议你阅读这篇文章。 它解释了一个真实案例的差异。

从文章引用

可以看到实现类还依赖于模板方法类,如果想要改变algorithm的某些步骤,这种依赖性会导致改变模板方法;另一方面,策略将完全封装algorithm,从而实现类来完全定义一个algorithm,因此,如果有任何变化需要改变以前编写的类的代码,这是我selectdevise类的策略的主要原因。

模板方法的一个特点是模板方法控制algorithm。 在其他情况下,这可能是一件好事,但在我的问题中,这限制了我devise类。 另一方面,策略不能控制algorithm的步骤,这使得我可以添加完全不同的转换方法。 因此,在我的情况下,战略可以帮助我执行。

策略的一个缺点是代码冗余太多,代码共享less。 正如在本文介绍的例子中显而易见的,我必须一次又一次地在四个类中重复相同的代码。 所以很难维护,因为如果我们的系统的执行,如所有常见的步骤4改变,那么我将不得不在所有的五个类别中更新它。 另一方面,在模板方法中,我只能改变超类,这些改变反映到子类中。 因此,模板方法在类之间提供了非常less量的冗余和大量的代码共享。

策略也允许在运行时改变algorithm。 在模板方法中,必须重新初始化对象。 这一战略特点提供了大量的灵活性。 从devise的angular度来看,人们不得不把构图放在inheritance之上。 所以使用战略模式也成为发展的首选。“

模板模式与策略模式类似。 这两种模式在范围和方法上有所不同。

策略用于允许调用者改变整个algorithm,例如如何计算不同types的税,而模板方法用于改变algorithm中的步骤。 因此,策略更粗糙。 该模板允许在后续操作中进行更细粒度的控制,但是允许这些细节的实现有所不同。

另一个主要区别是,Strategy方法使用inheritance,而Template方法使用inheritance。 在策略中,该algorithm被委托给主题将要引用的另一个xxxStrategy类,但是使用Template来对基础进行子类化并覆盖方法以进行更改。

http://cyruscrypt.blogspot.com/2005/07/template-vs-strategy-patterns.html

在策略模式中,子类正在运行显示并控制algorithm。 这里的代码是在子类中重复的。 该algorithm的知识和如何实现它分布在许多类。

在模板模式中,基类有algorithm。 它最大化了子类之间的重用。 由于algorithm在一个地方,基类保护它。

模板方法:

  1. 它基于inheritance
  2. 定义不能被子类改变的algorithm的骨架。 只有某些操作可以在子类中重写
  3. 父类完全控制algorithm ,仅将具体的步骤与具体的类进行区分
  4. 绑定是在编译时完成的

Template_method结构:

在这里输入图像说明

战略:

  1. 它基于授权/组成
  2. 通过修改方法的行为来改变对象的内容
  3. 它用于在algorithm族之间切换
  4. 它在运行时通过在运行时用其他algorithm完全replace一个algorithm来改变对象的行为
  5. 绑定在运行时完成

战略结构:

在这里输入图像说明

看看模板方法和策略文章,以更好的理解。

相关文章:

JDK中的模板devise模式,无法find一个定义要按顺序执行的方法集合的方法

战略格局的现实世界范例

模板模式:

Template方法是让子类重新定义algorithm的某些步骤,而不改变基类中定义的algorithm的主要结构和步骤。 模板模式通常使用inheritance,所以可以在基类中提供algorithm的通用实现,如果需要,子类可以select覆盖它。

 public abstract class RobotTemplate { /* This method can be overridden by a subclass if required */ public void start() { System.out.println("Starting...."); } /* This method can be overridden by a subclass if required */ public void getParts() { System.out.println("Getting parts...."); } /* This method can be overridden by a subclass if required */ public void assemble() { System.out.println("Assembling...."); } /* This method can be overridden by a subclass if required */ public void test() { System.out.println("Testing...."); } /* This method can be overridden by a subclass if required */ public void stop() { System.out.println("Stopping...."); } /* * Template algorithm method made up of multiple steps, whose structure and * order of steps will not be changed by subclasses. */ public final void go() { start(); getParts(); assemble(); test(); stop(); } } /* Concrete subclass overrides template step methods as required for its use */ public class CookieRobot extends RobotTemplate { private String name; public CookieRobot(String n) { name = n; } @Override public void getParts() { System.out.println("Getting a flour and sugar...."); } @Override public void assemble() { System.out.println("Baking a cookie...."); } @Override public void test() { System.out.println("Crunching a cookie...."); } public String getName() { return name; } } 

注意在上面的代码中,go()algorithm的步骤总是相同的,但是子类可能会定义一个不同的配方来执行特定的步骤。

战略模式:

策略模式是让客户在运行时select具体的algorithm实现。 所有algorithm都是独立的,独立的,但实现一个通用的接口,并没有定义algorithm中的特定步骤的概念。

 /** * This Strategy interface is implemented by all concrete objects representing an * algorithm(strategy), which lets us define a family of algorithms. */ public interface Logging { void write(String message); } /** * Concrete strategy class representing a particular algorithm. */ public class ConsoleLogging implements Logging { @Override public void write(String message) { System.out.println(message); } } /** * Concrete strategy class representing a particular algorithm. */ public class FileLogging implements Logging { private final File toWrite; public FileLogging(final File toWrite) { this.toWrite = toWrite; } @Override public void write(String message) { try { final FileWriter fos = new FileWriter(toWrite); fos.write(message); fos.close(); } catch (IOException e) { System.out.println(e); } } } 

有关完整的源代码,请查看我的github 存储库 。

策略作为抽象类作为接口和模板方法公开。 这在框架中通常使用很多。 例如,Spring框架的MessageSource类是用于parsing消息的策略接口。 客户端使用此接口的特定实现(策略)。

和AbstractMessageSource相同的接口的抽象实现,它具有parsing消息的通用实现,并公开了resolveCode()抽象方法,以便子类可以以他们的方式实现它们。 AbstractMessageSource是模板方法的一个例子。

http://docs.spring.io/spring/docs/4.1.7.RELEASE/javadoc-api/org/springframework/context/support/AbstractMessageSource.html

在这种devise模式的模板方法中,一个或多个algorithm步骤可以被子类覆盖,以允许不同的行为,同时确保仍然遵循总体algorithm(Wiki)。

模式名称模板方法意味着它是什么。 说我们有一个方法CalculateSomething(),我们想要模板这个方法。 这个方法将在基类中声明一个非虚方法。 说这个方法看起来像这样。

 CalculateSomething(){ int i = 0; i = Step1(i); i++; if (i> 10) i = 5; i = Step2(i); return i; 

} Step1和Step2方法的实现可以由派生类给出。

在战略模式中,没有基础提供的实现(这就是为什么基础实际上是类图中的一个接口的原因)

典型的例子是sorting。 根据需要sorting的对象数量,创build合适的algorithm类(合并,冒泡,快速等),并将整个algorithm封装在每个类中。

现在我们可以实现sorting作为模板方法吗? 当然你可以,但是你不会find太多/任何共同点被抽象出来并放置在基础实现中。 所以它打破了模板方法模式的目的。

战略devise模式

  • 支持构图。
  • 为您提供了在运行时更改对象行为的灵活性。
  • 客户端代码和解决scheme/algorithm代码之间的耦合较less。

模板方法devise模式

  • 有利于inheritance构图
  • 在您的基类中定义algorithm。 可以在子类中定制单独的algorithm片段。
Interesting Posts