模板方法模式

模式说明

有这样一些对象,他们都要执行若干动作,这些动作中多数类似或完全相同,例如在不同客户在到银行处理业务,都需要取号,排队,与柜员交流,处理后对服务评分等。在这里取号,排队,评分动作是完全相同的,与柜员交流的细节可能不同,可能是办理存款业务,也可能是取款,购买基金等。针对此类场景,可以将设置一个抽象模板类,类内声明相关方法,再定义一个驱动方法来调用这些相关方法。这样子类继承抽象模板类后自动复用了大部分的代码,对于具体实现中有区别的细节,在子类中重写即可。

本示例以大学生和小学生入学活动为例,将入学活动中相同的部分放在抽象模板类中,子类继承时自动获得,而子类中不同部分在抽象类中定义为抽象方法或钩子方法,具体实现延迟到子类中。

结构

抽象模板类: 定义方法骨架,并确定一个procedure方法,将需要执行的方法集中放置其中,客户端调用该procedure即可统一执行多个既定的方法。该类内方法分为普通方法,抽象方法和钩子方法。 具体实现类: 继承抽象模板类,按自身情况实现其中的各种方法。

代码演示

package com.yukiyama.pattern.behavior;

/**
 * 模板方法模式
 */
public class TemplateMethodDemo {

    public static void main(String[] args) {
        Admission ad1 = new CollegeAdmission();
        System.out.println("====大学生的入学活动====");
        ad1.templateProcedure();
        System.out.println("====小学生的入学活动====");
        Admission ad2 = new PrimarySchoolAdmission();
        ad2.templateProcedure();
    }

}

/**
 * 抽象模板类
 * 定义方法骨架,并确定一个procedure方法,将需要执行的方法集中放置,客户端
 * 调用该procedure即可统一执行多个既定的方法。该类内方法分为普通方法,抽象
 * 方法和钩子方法。普通方法是所有子类均的共同步骤,且细节一致。抽象方法也是
 * 共同步骤,但细节不同,延迟到子类中实现。钩子方法分为简单钩子和挂载钩子方法。
 * 对于简单钩子方法,抽象类中将其声明为空方法体的普通方法,子类可以选择重写
 * 扩展,若不重写则执行空方法体(相当于不执行)。对于挂载钩子方法,抽象类中先
 * 定义一个用于判断是否执行挂载钩子方法的返回boolean类型的抽象方法。再在挂载
 * 钩子方法中通过一个if-else判断上述boolean类型方法的返回值,true则执行,
 * false则进入空分支(相当于不执行)。boolean类型抽象方法延迟到子类实现,由
 * 子类决定是否进入执行挂载钩子方法的执行分支。挂载钩子方法本身在抽象类中可以
 * 作为普通方法,这样子类中就不必重写了。
 */
abstract class Admission{
    public void templateProcedure() {
        healthCheck();
        payTuition();
        militaryTraining();
        morningExercise();
        registerClasses();
    }
    public void healthCheck() {
        System.out.println("到教育部指定体检机构体检。");
    }
    public void payTuition() {
        System.out.println("通过教育部统一学费缴纳平台缴费。");
    }
    // 将军训设置为一个简单钩子方法,具体实现类可选择实现
    public void militaryTraining() {};
    // 将早操设置为一个挂载钩子方法,具体实现类中先实现hasMorningExcercise,
    // true则执行(要做早操),false不执行(进入空分支,相当于不执行)
    public abstract boolean hasMorningExcercise();
    public void morningExercise() {
        if(hasMorningExcercise()) {
            System.out.println("要做早操。");
        } else {}
    }
    public abstract void registerClasses();
    public abstract void choseDormitory();
}

/**
 * 具体实现类
 * 继承抽象模板类,按自身情况实现其中的各种方法。
 * 下例是大学生入学活动类。
 */
class CollegeAdmission extends Admission {
    // 具体实现类中扩展钩子方法
    @Override
    public void militaryTraining() {
        System.out.println("高校新生入学后要参加军训。");
    }
    // 重写抽象类中的挂载钩子方法的触发方法
    @Override
    public boolean hasMorningExcercise() {
        return false;
    }
    @Override
    public void registerClasses() {
        System.out.println("高校新生课程注册由新生自行完成。");
    }

    @Override
    public void choseDormitory() {
        System.out.println("高校新生入学后请在校内宿舍系统内选择宿舍。");
    }
}

/**
 * 具体实现类
 * 下例是小学生入学活动类。
 */
class PrimarySchoolAdmission extends Admission{
    // 没有实现抽象类中的简单钩子方法militaryTraining
    // 重写抽象类中的挂载钩子方法的触发方法
    @Override
    public boolean hasMorningExcercise() {
        return true;
    }
    @Override
    public void registerClasses() {
        System.out.println("小学新生课程注册由班主任完成。");
    }
    
    @Override
    public void choseDormitory() {
        System.out.println("小学新生原则上不提供校内住宿,特殊情况请单独申请。");
    }
}

Last updated