爱学it学无止境

模版方法模式角色如下:

AbstractClass(抽象类):定义了一个模板方法(Template Method),其中包含了算法的框架及具体步骤的声明,部分步骤可以是抽象方法,由具体子类实现。

ConcreteClass(具体子类) :继承自抽象类,并实现了其中定义的抽象方法,完成算法中具体步骤的实现。

UML 类图结构很简单,就一个继承关系,模板方法模式的重点在 AbstractClass(抽象类)上,AbstractClass 由一个模板方法和若干个基本方法构成:

模板方法:定义了一套算法的骨架,按某种顺序调用其包含的基本方法。

基本方法:是算法骨架/流程的某些步骤进行具体实现,包含以下几种类型:

▪ ▪ 抽象方法:在抽象类中声明,必须由具体子类实现。

▪ ▪ 具体方法:在抽象类中已经实现,具体子类中可以选择重写它。

▪ ▪ 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

基本实现

抽象类 Abstract Class

AbstractClass 是抽象类,其实也就是一抽象模板,定义并实现了一个模版方法。这个模版方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

public abstract class AbstractClass {

    // 模板方法
    public final void templateMethod() {
        abstractMethod();  // 步骤1
        concreteMethod();  // 步骤2
        emptyMethod();     // 步骤3
        if(judgeMethod()){ // 步骤4
            System.out.println("任务完成");
        }
    }

    // 抽象方法,子类必须实现
    protected abstract void abstractMethod();

    // 具体方法,子类选择性实现
    protected void concreteMethod(){
        System.out.println("具体方法完成步骤2");
    }

    // 钩子方法(空方法),子类选择性实现
    protected void emptyMethod(){

    }

    // 钩子方法(判断方法),子类选择性实现
    protected boolean judgeMethod(){
        return false;
    }

}

具体子类 ConcreteClass

ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个 AbstractClass 都可以有任意多个 ConcreteClass 与之对应,而每一个 ConcreteClass 都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

▪ 具体子类A

具体子类A给出了抽象方法的具体实现,并且重写判断钩子方法:

public class ConcreteClassA extends AbstractClass{

    @Override
    protected void abstractMethod() {
        System.out.println("ConcreteClassA 完成步骤1");
    }

    @Override
    protected boolean judgeMethod(){
        return true;
    }

}

▪ 具体子类B

具体子类B给出了抽象方法的具体实现,并且重写空实现的钩子方法:

public class ConcreteClassB extends AbstractClass{

    @Override
    protected void abstractMethod() {
        System.out.println("ConcreteClassB 完成步骤1");
    }

    @Override
    protected void emptyMethod(){
        System.out.println("ConcreteClassB 完成步骤3");
    }

}

客户端 Client

AbstractClass template = new ConcreteClassA();
template.templateMethod();

System.out.println("*****************");

template = new ConcreteClassB();
template.templateMethod();

输出结果如下:

ConcreteClassA 完成步骤1
具体方法完成步骤2
任务完成
*****************
ConcreteClassB 完成步骤1
具体方法完成步骤2
ConcreteClassB 完成步骤3

ConcreteClassAConcreteClassB 的算法骨架相同,但具体个别步骤不同。

这里需要注意的是,钩子方法可以是空方法,可以是判断方法,通过钩子方法的重写可以将模板方法(templateMethod)中的某个步骤移除或加入。