在我们的开发过程中,对于某些操作流程的步骤可能是一样的,但是步骤的具体实现却会有所变化,所以将这些固定步骤抽取成一个模板,再修改不同的实现就是模板方法模式。
第十五章 抓住问题核心——模板方法模式
1.定义
定义一个操作中的算法的框架,而将一些步骤延迟到子类中去,使子类不可改变算法的结构,但可以重定义该算法的某些特定步骤。
2.使用场景
1).多个子类有公有的方法,并且逻辑基本相同。
2).重要、复杂的算法可以把核心算法设计为模板方法,周边的细节功能由各个子类实现。
3).重构时,模板方法模式是一个经常使用的模式,将相同代码抽取到父类中,然后通过钩子方法约束其行为。
什么是钩子方法,几经百度,暂时理解为,当需要特定逻辑时才需要重写的方法,否则为父类默认方法。
3.简单实现
以一个自我构思的计算机开机过程为例,计算机开机的过程一般都是固定的,但是可能不同的设置可能会导致有特别的操作,比如会检查是否设置了密码、检查防火墙是否开启、是否开启系统更新自动检查。
先定义一个计算机类,让相同的步骤抽取出来:
public abstract class Computer {
public void powerOn() {
System.out.println("按下开机键");
}
public void checkHardware() {
System.out.println("检查硬件");
}
public void loadOS() {
System.out.println("加载系统");
}
public void login() {
System.out.println("登录系统");
}
public final void startUp() {
System.out.println("计算机准备开机了");
powerOn();
checkHardware();
loadOS();
login();
System.out.println("计算机成功开机");
}
}
这个 startUp() 方法就是控制逻辑流程的,一般逻辑不会变,所以用 final 修饰,使其不可修改。
普通计算机不需要什么特别的操作,所以不重写任何方法:
public class CommonComputer extends Computer {
}
public class ProgrammerCompuer extends Computer {
@Override
public void login() {
super.login();
System.out.println("程序员的电脑需要输入密码才能完成开机");
}
}
军用电脑一不小心就会泄露国家机密,所以要严加防范:
public class MilitaryComputer extends Computer {
@Override
public void checkHardware() {
super.checkHardware();
System.out.println("军用电脑检查完硬件后还得检查一下防火墙是否开启");
}
@Override
public void loadOS() {
super.loadOS();
System.out.println("军用电脑加载系统后还得检查一下是否有新的补丁需要安装");
}
@Override
public void login() {
super.login();
System.out.println("军用电脑也得输入密码才能完成开机");
}
}
CommonComputer mCommonComputer = new CommonComputer();
mCommonComputer.startUp();
ProgrammerCompuer mProgrammerCompuer = new ProgrammerCompuer();
mProgrammerCompuer.startUp();
MilitaryComputer mMilitaryComputer = new MilitaryComputer();
mMilitaryComputer.startUp();
打印如下:
可以看到,几种不同的计算机,有的会某些步骤加入一些特别的操作,但是总的流程是不会变的,都是经过“按下开机键”、“检查硬件”、“加载系统”、“登录系统”四个步骤才能成功开机的这样一个流程。 Android 源码中其实有好多模板方法模式, AsyncTask 就是一个典型,在执行 execute() 方法后,它会依次执行 onPreExecute() 、doInBackground() 、 onPostExecute() 方法,流程不会变,但是我们可以在这些方法中实现特定操作。另外 Activity 的生命周期 onCreate() 、 onStart() 、 onResume() 也是顺序执行的,它也可以看作是模板方法的体现。
4.总结
模板方法模式总结起来就四个字:流程封装,把固定流程封装到一个 final 方法中,并且在父类中提取共用代码,让子类可以定制这个流程中的某些甚至是全部步骤,提升代码的复用率,提供更好的扩展性。
优点:
1).封装不变部分,扩展可变部分。
2).提取公共部分代码,便于维护。
缺点:
1).加大代码阅读的难度,会让用户难以理解。