深入理解模板模式
定义:定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
说到步骤,我想对于我们程序员来说,最熟悉的当然是一个需求的一个开发流程了,下面我们就从开发流程来了解模板模式。
那么开发流程具体有哪些步骤,请看:
1. 需求评审(产品,开发,测试参与)
2. 开始开发
3. 提交测试
4. 功能上线
当然这是开发过程中没有修改需求的情况,然后我们定义一个算法步骤:
public abstract class DevelopmentProcess {
//需求评审
protected abstract void requirementReview();
//开始开发
protected abstract void development();
//提交测试
protected abstract void submitTest();
//功能上线
protected abstract void goOnline();
//完整开发流程
final public void run(){
this.requirementReview();
this.development();
this.submitTest();
this.goOnline();
}
}
写了这么多方法,然后我们再定义个子类,来继承它:
public class DevelopmentProcessTest extends DevelopmentProcess{
@Override
protected void requirementReview() {
System.out.println("需求评审");
}
@Override
protected void development() {
System.out.println("开始开发");
}
@Override
protected void submitTest() {
System.out.println("提交测试");
}
@Override
protected void goOnline() {
System.out.println("功能上线");
}
public static void main(String[] args) {
DevelopmentProcessTest developmentProcessTest = new DevelopmentProcessTest();
developmentProcessTest.run();
}
}
然后我们运行一下代码,将会得到如下结果:
需求评审
开始开发
提交测试
功能上线
这就是一个简单的模板模式,在此你有没有很奇怪,你为什么定义方法的时候,全是 protected 类型的方法,目的是为了什么,那么在使用模板模式的时候需要注意一下:
1. 抽象模板中的基本方法尽量设置为 protected类型
2. 符合迪米特法则(如果不清楚则请翻看鄙人的设计模式七大原则)
3. 不暴露的属性和方法尽量不要设置为 protected 类型,如果不是必须访问,尽量不要扩带其他的访问权限。
模板优化:
如果类似上面这种写法,大家觉不觉得有些问题,就是具体的实现交给了子类,子类想怎么玩就怎么玩,为了防止恶意操作呢,一般模板方法上都加上final关键字,不允许被覆盖。
public abstract class DevelopmentProcess {
//需求评审
protected final void requirementReview(){
System.out.println("需求评审");
}
//开始开发
protected final void development(){
System.out.println("开始开发");
}
//提交测试
protected final void submitTest(){
System.out.println("提交测试");
}
//功能上线
protected final void goOnline(){
System.out.println("功能上线");
}
//完整开发流程
final public void run(){
this.requirementReview();
this.development();
this.submitTest();
this.goOnline();
}
}
再一次执行,则还是得到刚才执行的结果,但是这样做的好处,具体过程封装在父类,子类是不知道过程的。
突然有一天,部门不小心招来了一位小明同学,开发老是出问题,让他开发一个功能,老是把之前好的代码修改了,对于测试来说,一个功能要反复测试几遍,非常闹心。(一般开发过程都需要回归测试,因为开发过程中有bug,修改后总得在测试一遍吧,这里便于理解,出此下策,对不起了,小明同学)
怎么办呢?对于我们刚才的流程好像不管用了,需要做回归测试,添加一个步骤?no no no ,如果你的模板方法比较复杂,一修改,可能子类就需要跟着改了,这不就违背了开闭原则。
那么怎么办呢?一思考,并不是所有的开发人员都需要 回归测试,可以加一个判断,针对不同开发人员,处理方式不一致。
钩子方法
修改后的模板方法类:
public abstract class DevelopmentProcess {
//需求评审
protected final void requirementReview(){
System.out.println("需求评审");
}
//开始开发
protected final void development(){
System.out.println("开始开发");
}
//提交测试
protected final void submitTest(){
System.out.println("提交测试");
}
//功能上线
protected final void goOnline(){
System.out.println("功能上线");
}
//完整开发流程
final public void run(){
this.requirementReview();
this.development();
this.submitTest();
if (IsRepeatTest()){
System.out.println("进行回归测试");
}
this.goOnline();
}
//钩子方法
protected abstract boolean IsRepeatTest();
}
修改测试类:
public class DevelopmentProcessTest extends DevelopmentProcess{
@Override
protected boolean IsRepeatTest() {
return true;
}
}
我们来测试一下效果:
public static void main(String[] args) {
DevelopmentProcess developmentProcess = new DevelopmentProcessTest();
developmentProcess.run();
}
最终得到如下结果:
需求评审
开始开发
提交测试
进行回归测试
功能上线
这就是模板模式,是不是很简单,在开发过程中,你是不是也常常使用到过,但是并不知道这叫模板模式。