谁能给我解释一下模板方法模式和策略模式的区别是什么?

据我所知,它们99%是一样的——唯一的区别是 模板方法模式有一个抽象类作为基础 类,而策略类使用已实现的接口 由每个具体的策略类。

然而,就客户端而言,它们是以完全相同的方式被消费的——这是正确的吗?


当前回答

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

模式名Template方法的意思是它是什么。假设我们有一个方法calculatessomething(),我们想要创建这个方法的模板。此方法将在基类中声明为非虚方法。假设这个方法是这样的。

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

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

在策略模式中,基类没有提供实现(这就是为什么基类实际上是类图中的接口)。

经典的例子是排序。根据需要排序的对象数量,创建适当的算法类(merge, bubble, quick等),并将整个算法封装在每个类中。

现在我们可以将排序实现为模板方法了吗?当然可以,但是您不会发现有太多/任何共性可以抽象出来并放置在基本实现中。因此,它违背了模板方法模式的目的。

其他回答

两者都非常相似,客户端代码以类似的方式使用它们。与上面最流行的答案不同,两者都允许在运行时选择算法。

The difference between the two is that while the strategy pattern allows different implementations to use completely different ways of the achieving the desired outcome, the template method pattern specifies an overarching algorithm (the "template" method) which is be used to achieve the result -- the only choice left to the specific implementations (sub-classes) are certain details of the said template method. This is done by having the the template method make call(s) to one or more abstract methods which are overridden (i.e. implemented) by the sub-classes, unlike the template method which itself is not abstract and not overridden by the sub-classes.

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

You probably mean template method pattern. You are right, they serve very similar needs. I would say it is better to use template method in cases when you have a "template" algorithm having defined steps where subclasses override these steps to change some details. In case of strategy, you need to create an interface, and instead of inheritance you are using delegation. I would say it is a bit more powerful pattern and maybe better in accordance to DIP - dependency inversion principles. It is more powerful because you clearly define a new abstraction of strategy - a way of doing something, which does not apply to template method. So, if this abstraction makes sense - use it. However, using template method may give you simpler designs in simple cases, which is also important. Consider which words fit better: do you have a template algorithm? Or is the key thing here that you have an abstraction of strategy - new way of doing something

模板方法的例子:

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

这里你继承了application,并替换了init, run和done的操作。

策略的例子:

array.sort (IComparer<T> comparer)

在这里,当编写比较器时,您不继承数组。数组将比较算法委托给比较器。

继承与聚合(is-a与has-a)。这是实现同一目标的两种方法。

这个问题显示了选择之间的一些权衡:继承还是聚合

两者的主要区别在于具体算法的选择。

对于Template方法模式,这是在编译时通过子类化模板实现的。每个子类通过实现模板的抽象方法提供不同的具体算法。当客户端调用模板外部接口的方法时,模板会根据需要调用它的抽象方法(内部接口)来调用算法。

class ConcreteAlgorithm : AbstractTemplate
{
    void DoAlgorithm(int datum) {...}
}

class AbstractTemplate
{
    void run(int datum) { DoAlgorithm(datum); }

    virtual void DoAlgorithm() = 0; // abstract
}

相反,策略模式允许在运行时通过包含来选择算法。具体算法由单独的类或函数实现,这些类或函数作为参数传递给策略的构造函数或setter方法。为这个参数选择哪种算法可以根据程序的状态或输入动态变化。

class ConcreteAlgorithm : IAlgorithm
{
    void DoAlgorithm(int datum) {...}
}

class Strategy
{
    Strategy(IAlgorithm algo) {...}

    void run(int datum) { this->algo.DoAlgorithm(datum); }
}

总而言之:

模板方法模式:通过子类化来选择编译时算法 策略模式:通过包容选择运行时算法

我认为这两种模式的类图显示了差异。

策略 在类中封装算法 图片链接

模板方法 将算法的精确步骤推迟到子类 链接到图片