目录
介绍
在面向对象开发过程中,通常会遇到这样的一个问题,我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序,但是,某些步骤的具体实现是未知的,或者说某些步骤的实现是会随着环境的变化而变化的,例如,执行程序的流程大致如下:1、检查代码的正确性;2、链接相关的类库;3、编译相关的代码;4、执行程序。对于不同的程序设计语言,上述几个步骤的具体逻辑都是不一样的,但是,它们的执行顺序是固定的,这类问题的解决方法就是我们要讲的模板方法模式。
定义
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
使用场景
1、多个子类有公有的方法,并且逻辑基本相同时;
2、重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现;
3、重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束子类行为;
代码实现
我们以电脑开机为例,简单介绍一下模板方法模式的思想,比如打开电脑时需要开启电源、检查硬件、加载系统、登录这四个步骤,不管任何电脑这四步流程都是一致的,所以我们可以抽象电脑开机流程如下:
public abstract class AbstractComputer {
protected void powerOn() {
System.out.println("开启电源");
}
protected void checkHardware() {
System.out.println("检查硬件");
}
protected void loadOS() {
System.out.println("加载系统");
}
protected void login() {
System.out.println("登录");
}
protected final void startUp() {
powerOn();
checkHardware();
loadOS();
login();
}
}
按下电源键开机后,会执行startUp方法,在该方法中会按照固定的流程顺序去检查这四步,我们把该方法修饰为final,就是为了保证流程顺序的正确性,禁止子类修改顺序,子类可以在每个流程步骤中去实现自己特有的逻辑,比如码农的电脑没有任何特殊,伪代码如下:
public class CoderComputer extends AbstractComputer {
@Override
protected void login() {
System.out.println("没有密码,可以直接登录");
}
}
我们码农就是砖,没有任何秘密,但是财务就不一样了,钱都在他们手里管着呢,所以他们的电脑开机时要求就严格了,伪代码如下:
public class FinancialComputer extends AbstractComputer {
@Override
protected void checkHardware() {
System.out.println("检查财务软件是否安装");
}
@Override
protected void login() {
System.out.println("必须输入财务系统密码才能登录");
}
}
可以看到,两个子类的差别就是每一个细节流程可以特殊化,但是startUp是不能变的,它就是一个固定好的流程、套路,这就是模板方法的思想了。
模板方法用四个字概括就是:流程封装!!!也就是把某个固定的流程封装到一个final函数中,并且让子类能够定制这个流程中的某些或者所有步骤,这就要求父类提取共用的代码,定制好流程,提升代码的复用率,同时也带来更好的可扩展性。