模板方法模式简单介绍
在面向对象开发过程中,通常会遇到这样的一个问题,我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序,但是,某些步骤的具体实现是未知的,或者说某些步骤的实现是会随着环境的变化而改变的,例如,执行程序的流程大致如下:
- (1) 检查代码的正确性
- (2)链接相关的类库
- (3)编译相关代码
- (4)执行程序
对于不同的程序设计语言,上述 4 个步骤都是不一样的,但是,它们的执行流程是固定的,这类问题的解决方法就是我们接下来要介绍的模板方法模式。
模板方法模式的定义
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法的使用场景
- (1)多个子类有公有的方法,并且逻辑基本相同时。
- (2)重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类去实现。
- (3)重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
模板方法模式的 UML 类图
角色介绍:
- AbstractTemplate:抽象类,定义了一套算法框架。
- ConcreteImplA、ConcreteImplB: 具体实现类。
模板方法模式实战
/**
* 抽象的Computer
*/
public class AbstractComputer {
protected void powerOn() {
//开启电源
}
protected void checkHardware() {
//硬件检测
}
protected void loadOS() {
//载入操作系统
}
protected void login() {
//进入系统
}
/**
* 启动计算机方法,步骤固定为 开启电源、硬件检测、载入操作系统、进入系统
*/
public final void startUp(){
powerOn();
checkHardware();
loadOS();
login();
}
}
/**
* 程序员计算机
*/
public class CoderComputer extends AbstractComputer {
@Override
protected void login() {
//程序员只需要进行用户和密码的验证即可进入系统
}
}
/**
* 军用计算机
*/
public class MilitaryComputer extends AbstractComputer {
/**
* 军用计算机处理要检测硬件之外还需要检测硬件防火墙
*/
@Override
protected void checkHardware() {
super.checkHardware(); //检测硬件
//检测硬件防火墙
}
@Override
protected void login() {
//进行指纹识别等复杂的用户验证
}
}
从上面的例子可以看到,在 startUP 方法中有一些固定的步骤,依次为开启电源、检测硬件、加载系统、用户登录 4 个步骤,这 4 个步骤是计算机开机过程中不会变动,但是不同的用户的这几个步骤的实现可能各不相同,因此,子类需要覆写相应的方法来进行自定义处理,这里需要注意的是 startUP 为 final 方法,这样就保证了逻辑流程不能被子类修改,子类只能够改变某一步骤中的具体实现,这样就保证了这个逻辑流程的稳定性。startUP 中的这几个算法步骤我们可以称为是一个套路,也称为模板方法,这也是该模式的由来。
总结
模板方法模式用 4 个字概况就是:流程封装。也就是吧某个固定的流程封装到一个 final 函数中,并且让子类能够定制这个流程中的某些或者所有步骤,这就要求父类提取共用的代码,提升代码的复用率,同时也带了了更好的扩展性。
优点:
- (1)封装不变部分,扩展可变部分。
- (2)提取公共部分代码,便于维护。
缺点:
- 模板方法会带来代码阅读的难度,会让用户觉得难以理解。