1.前言
套用书中的定义:定义一个操作算法的骨架,将一些步骤延迟到子类,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤
说人话就是在父类中定义一系列步骤方法,扩展给子类实现,然后在父类中通过this指针调用这一系列步骤,怎么调用,由父类规定,谁干活,子类来干。
比如,项目经理张罗了一揽子的需求,分为A,B,C…需求,根据实际情况,安排任务排期,这小子不干活,给下边的程序员干,程序员原则上不能修改排期的顺序,不能随便删除其中的某个需求,你可以不干,给个空实现,只要项目经理允许,他不炸毛,也就无所谓。
UML:
2.示例
以上例子,只是为了帮助理解说明,关键还是要理解“定义一个操作算法的骨架,将一些步骤延迟到子类”这句话,以一个例子来说明,就比较清晰了。
以操作系统启动为例,我们在抽象层面上简单将启动流程定义四个步骤:BIOS自检、系统引导、启动内核、初始化系统,每个步骤的细节操作交给具体的操作系统去实现
首先定义一个抽象类,在抽象类中定义操作的每一个步骤,然后再定义一个方法,按照正确执行流程执行这些方法,需要注意的是,该方法需要声明为finl类型的,不允许被改变,规矩是死的
/**
* @description: 抽象层
* @version: 1.0
*/
public abstract class AbstractOperatingSystem {
/*
该方法序声明为final类型 ,在该方法中规定流程
*/
public final void init(){
//bois自检
this.bios_check();
//系统引导
this.sys_guide();
//启动内核
this.boot_kernel();
//系统初始化
this.init_sys();
}
public abstract void bios_check();
public abstract void sys_guide();
public abstract void boot_kernel();
public abstract void init_sys();
}
对抽象类进行具体的实现
/**
* @description: 具体实现类
* @version: 1.0
*/
public class LinuxOperatingSystem extends AbstractOperatingSystem {
@Override
public void bios_check() {
System.out.println("Linux:Bios自检");
}
@Override
public void sys_guide() {
System.out.println("Linux:系统引导");
}
@Override
public void boot_kernel() {
System.out.println("Linux:启动内核");
}
@Override
public void init_sys() {
System.out.println("Linux:初始化系统");
}
}
测试类:
/**
* @description: test
* @version: 1.0
*/
public class Test {
public static void main(String[] args) {
AbstractOperatingSystem operatingSystem = new LinuxOperatingSystem();
//启动
operatingSystem.init();
}
}
input:
Linux:Bios自检
Linux:系统引导
Linux:启动内核
Linux:初始化系统
如果对上述代码做一个总结,那就是父类规定了流程,这是硬性规定,不容改变,而子类对这些固定做了具体的实现,调用时,使用父类的流程去执行子类的代码,或者说,有一种反向控制的效果,即父类调动子类。
当然,子类怎么实现是子类的事情,包括空实现(只要父类允许这种情况发生),一般情况下,如果父类中有一些非必要步骤,在父类中可以给一个具体空实现方法,作为子类的可选实现步骤,比如上述的例子中,图形界面并不是一个必须项,那就可以添加一个具体的空方法,不要求子类必须实现,简单改造一下:
public abstract class AbstractOperatingSystem {
/*
该方法序声明为final类型 ,在该方法中规定流程
*/
public final void init(){
//bois自检
this.bios_check();
//系统引导
this.sys_guide();
//启动内核
this.boot_kernel();
//系统初始化
this.init_sys();
//启动图形接口
this.gui_init();
}
public abstract void bios_check();
public abstract void sys_guide();
public abstract void boot_kernel();
public abstract void init_sys();
public void gui_init(){
//nop
}
}
public class LinuxOperatingSystem extends AbstractOperatingSystem {
//override....
@Override
public void gui_init() {
System.out.println("Linux:启动图形接口");
}
}
public class Test {
public static void main(String[] args) {
AbstractOperatingSystem operatingSystem = new LinuxOperatingSystem();
//初始化
operatingSystem.init();
}
}
input:
Linux:Bios自检
Linux:系统引导
Linux:启动内核
Linux:初始化系统
Linux:启动图形接口
3.总结
模板设计模式平常用的会相对多一些,对于一些复杂公共流程可以用这种方式进行抽取,降低代码冗余,控制整体业务流程,很多的框架中都有这种设计的体现,比如一些数据库持久层框架,springweb容器的加载,配置加载等,或者再回想一下servlet的doGet doPost,总之,对于一些特定的流程处理,总是留了一个口子让你去实现,那基本就是模板设计了。
注:
图片来自:百度图片