模板方法模式简介
模板方法模式是一种行为型设计模式。
思想: 定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。
模板方法模式涉及到2个角色
- 抽象模板(Abstract Template):
定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。
定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。 - 具体模板(Concrete Template):
实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。
模板方法模式案例
案例:公司的上班情况,简单描述一下:公司有程序猿、测试、HR、项目经理等人,下面使用模版方法模式,记录下所有人员的上班情况。
定义了一个上班(算法)的骨架,包含以下步骤:
a、进入公司,b、打开电脑,c、上班情况,d、关闭电脑,e、离开公司
a、b、d、e我们在超类中已经实现,子类仅实现work这个抽象方法,记录每天的上班情况。
// 抽象模板
public abstract class Worker {
protected String name;
public Worker(String name) {
this.name = name;
}
// 记录一天的工作,相当于初始的算法
public final void workOneDay() {
System.out.println("-----------------work start ---------------");
enterCompany();
computerOn();
work();
computerOff();
exitCompany();
System.out.println("-----------------work end ---------------");
}
// 抽象工作,这里不实现,让具体的子类来实现
public abstract void work();
// 关闭电脑,定义基础的实现,后续子类可以覆盖编写自己的实现
public void computerOff() {
System.out.println(name + "关闭电脑");
}
// 打开电脑
public void computerOn() {
System.out.println(name + "打开电脑");
}
// 进入公司
public void enterCompany() {
System.out.println(name + "进入公司");
}
// 离开公司
public void exitCompany() {
System.out.println(name + "离开公司");
}
}
具体员工,程序猿:
public class ITWorker extends Worker{
public ITWorker(String name){
super(name);
}
@Override
public void work() {
System.out.println(name + "写程序-测bug-fix bug");
}
}
具体员工,HR:
public class HRWorker extends Worker{
public HRWorker(String name) {
super(name);
}
@Override
public void work() {
System.out.println(name + "看简历-打电话-接电话");
}
}
测试类:
public class Client {
public static void main(String[] args) {
Worker itWorker = new ITWorker("James");
itWorker.workOneDay();
Worker hrWorker = new HRWorker("Tom");
hrWorker.workOneDay();
}
}
运行结果:
模版方式里面也可以可选的设置钩子,比如现在希望记录程序员离开公司的时间,我们就可以在超类中添加一个钩子:
// 离开公司
public void exitCompany() {
if (isNeedPrintDate()){
System.out.print(LocalDateTime.now()+"-->");
}
System.out.println(name + "离开公司");
}
public boolean isNeedPrintDate() {
return false;
}
超类中添加了一个isNeedPrintDate方法,且默认返回false,不打印时间。如果某子类需要调用打印时间,可以复写改钩子方法,返回true,比如,程序猿复写了这个方法:
public class ITWorker extends Worker{
public ITWorker(String name){
super(name);
}
@Override
public void work() {
System.out.println(name + "写程序-测bug-fix bug");
}
@Override
public boolean isNeedPrintDate() {
return true;
}
}
运行结果: