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

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

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


当前回答

策略公开为接口,模板方法公开为抽象类。这通常在框架中被大量使用。 如。 Spring框架的MessageSource类是用于解析消息的策略接口。客户端使用该接口的特定实现(策略)。

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

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

其他回答

策略公开为接口,模板方法公开为抽象类。这通常在框架中被大量使用。 如。 Spring框架的MessageSource类是用于解析消息的策略接口。客户端使用该接口的特定实现(策略)。

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

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

模板模式:

模板方法是关于让子类重新定义算法的某些步骤,而不改变基类中定义的算法的主要结构和步骤。 模板模式通常使用继承,因此可以在基类中提供算法的泛型实现,如果需要,子类可以选择覆盖它。

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()算法步骤总是相同的,但是子类可能为执行特定步骤定义不同的配方。

策略模式:

策略模式是指让客户端在运行时选择具体的算法实现。所有算法都是隔离且独立的,但是实现了一个公共接口,并且没有在算法中定义特定步骤的概念。

/**
 * 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存储库。

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

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

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

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.

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

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

策略模式允许在多个可能的实现之间切换。它(通常)不是通过继承实现的,而是通过让调用者传入所需的实现来实现的。例如,允许为ShippingCalculator提供几种不同的计算税收的方法之一(可能是NoSalesTax实现和PercentageBasedSalesTax实现)。

有时候,客户端会告诉对象使用哪种策略。就像在

myShippingCalculator.CalculateTaxes(myCaliforniaSalesTaxImpl);

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