背景

在开发中,你肯定有遇到过这样一种场景:你知道某个方法的关键步骤以及执行顺序,但是里面有的具体步骤并清楚。你会怎么做?

比如你早上起床到公司,我们分解步骤:

  1. 起床洗漱
  2. 吃早餐
  3. 乘坐交通工具
  4. 到公司

我们已经确定这个步骤了,但是不同的人里面的细节可能会不一样。比如小明早餐吃的面包,小张吃的面条。小美坐的地铁,小花做的公交。

再举个例子,我们平时写简历会用到简历模板,不同的人写的内容不一样,模板一样。

模板方法模式是这样定义的:

定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。

这个定义看的云里雾里,我们直接代码来演示。

在写代码之前我们需要了解实现模板方法模式需要存在几个要素:

  • 抽象类:定义一个算法的基本骨架,需要有一个模板方法多个基本方法
  • 具体类:实现抽象类中定义的抽象方法

那么什么是模板方法呢?模板方法定义了算法骨架,并且包含了算法的执行顺序。

基本方法为算法中的一个步骤,需要实现或重写它。用于扩展。结构如下:

设计模式4之模板方法模式_java

模板方法的代码实现

首先创建一个抽象类:

public abstract class AbstractClass {
    //模板方法
    public void templateMethod() {
        specificMethod();
        abstractMethod1();
        abstractMethod2();
    }
    //具体方法
    public void specificMethod() {
        System.out.println("抽象类中的具体方法被调用...");
    }
    public abstract void abstractMethod1()//抽象方法1
    public abstract void abstractMethod2()//抽象方法2
}

这里面定义了模板方法,具体方法,抽象方法。模板方法里面包含了具体方法,和抽象方法。

具体的子类:

public class ConcreteClass extends AbstractClass {
    @Override
    public void abstractMethod1() {
        System.out.println("抽象方法1的实现被调用...");
    }

    @Override
    public void abstractMethod2() {
        System.out.println("抽象方法2的实现被调用...");
    }
}

这个子类继承了抽象类,里面实现了抽象方法。

测试代码如下:

public class TemplateMethodPattern {
    @Test
    public void test() {
        AbstractClass tm = new ConcreteClass();
        tm.templateMethod();
    }
}

我们调用模板方法,得到如下信息:

抽象类中的具体方法被调用...
抽象方法1的实现被调用...
抽象方法2的实现被调用...

关于模板方法模式的思考

从上面代码我们发现,模板方法templateMethod()的整体步骤是固定的,变的是具体方法和抽象方法里面的内容。我们通过对于抽象方法和具体方法,我们都可以通过继承方式去修改内容。

当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

我认为模板方法有以下几个好处:

  • 将不会变动的部分算法封装到父类实现,可变的部分通过继承来扩展。
  • 将同类的方法提取为公共的,也便于维护。
  • 父类控制行为,子类实现扩展。

所以当你在设计时,重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个 子类实现。