前言
好久没有写关于设计模式的文章啦,关于这个板块的文章我会不定期的更新,哈哈,很任性!
那今天呢我们要讲到的就是模板方法模式
什么是模板方法模式
讲这个模式并不是出于例外,而是对之前知识的一个回顾,可能之前在学习Sevlet或者Spring的时候呢,大家都接触了模板方法模式,只是不知道它叫这个名字而已,没有学习过的朋友呢也不用说现在就去看框架的文章,那是看不懂滴,跟着我们的文章走,还是很容易就可以懂得~
模板方法模式Template Method又称之为钩子方法模式,我们先来举个栗子
话说小李子(莱昂纳多)在18岁那年非常相当一名演员,然后向好莱坞投了简历,这小伙子年轻的时候长得特帅,演技也不错,好莱坞面试管通知它来面试,在试镜得时候也表现得非常不错,随后面试官通知他回去坐等结果,果不其然,过了两天之后就收到好莱坞得信件,通知他被录用啦,在19岁那年,小李子凭借《不一样的天空》里出色的演技获奥斯卡最佳男配提名了!
好我们来看看这个整个过程,不管是谁,想进入好莱坞必须要经过下面几个阶段
可以看出,投简历,试镜,以及最后收到结果都是固定得,但是唯独只有最后通知的方式,或者说结果是不固定得,并且在这个阶段中,小李子是无法直接去询问HR有没有通过,而只能是等待HR得通知,那么我们可以这么来看,投简历是一个方法,试镜是一个方法,收到通知是一个方法,都是固定不变得,主要是看HR最终执行得是什么通知方法,是电话通知呢?还是以正式得录用通知函来告知呢?
基本得框架是不变得,而调用具体哪个方法是可变的可控得,也就是说其中某个节点得方法暂时还不能确定,因此类似于这种情况呢,我们通常采用工厂方法模式,将这个节点得代码得实现转移给子类。可能理论难懂,那我们结合代码来看看吧~
模板方法模式示例
package com.marco.template;
public abstract class HollywoodInterview {
public void receiveResumes() {
System.out.println("HR收到简历");
}
public void callForInterview() {
System.out.println("HR发出面试通知并试镜");
}
public abstract void evaluate();
public void sendResult(String name) {
System.out.println("发送面试结果给" + name);
}
public final void interview(String name) {
receiveResumes();
callForInterview();
evaluate();
sendResult(name);
}
}
class PassInterview extends HollywoodInterview {
@Override
public void evaluate() {
System.out.println("过来上班");
}
}
class FailInterview extends HollywoodInterview {
@Override
public void evaluate() {
System.out.println("试试别家吧");
}
}
我们定义了一个抽象类HollywoodInterview,然后由它的子类去实现它得抽象方法,注意了,这里的interview()方法我是用final写死了得,意在不让子类去重写父类得方法,接下来我们安排小李子去面试
public class Artists {
public static void main(String[] args) {
HollywoodInterview interview = new PassInterview();
interview.interview("小李子");
}
}
不过,我们通常会使用匿名内部类的方式去实现接口并直接调用它的方法,效果也是一摸一样的
package com.marco.template;
public class Artists {
public static void main(String[] args) {
HollywoodInterview interview = new HollywoodInterview() {
@Override
public void evaluate() {
System.out.println("过来上班");
}
};
interview.interview("小李子");
}
}
通过上面得栗子,我们发现,我们得父类将整个流程体系规定得死死得,然后由子类重写它的抽象方法,通过这种方式起到一个约束和规范得作用,并且当我们调用interview()方法得时候我们发现,它像一个"钩子"一样,我只管调用evalute()方法,当我执行得时候,挂到哪一个子类得方法上就调用哪个子类重写之后的方法,反观,子类是无法重写并修改父类得interview()方法。
因此,这就是为什么我们也称他为"钩子"方法得原因,他还有一个好记得别名,叫
“好莱坞原则:Don’t call me, we’ll call you back”
艺人只能够把简历递给娱乐公司,试镜之后,只能被动得等待安排,需要你的时候我就传呼你,不需要你的时候,你爱干啥干啥,与我无瓜~
使用模板方法得场景
那说了半天,什么时候该使用模板方法呢?
其实根据上面得简单得栗子不难发现,父类有几个步骤是固定不变得,能变动得就只有抽象方法了,因此,当我们实现一个算法,整体得步骤很固定,但是某些地方很容易变动时,那么这一部分我们可以单独抽离出来为一部分,通过子类重写父类抽象方法得方式,实现方法得运转。
在实际开发中,也有很多地方使用到了模板方法模式,例如我们得
- 数据库访问封装
- Servlet关于doPost、doGet方法得调用
- Hibernate模板程序
- spring-JDBCTemplate等等
学习过前面得Servelt,对于doPost、doGet是再熟悉不过了,我们通过子类继承父类HttpServlet的方式,重写它的doGet()和doPost()方法,而service()就好比那个模板,当页面的请求过来的时候,优先会调用service()方法,然后会判断具体是以什么方式请求,来决定调用哪种方法,其实我们向上追溯到HttpServlet的父类GenericServlet时会发现,这个service()方法就是一个抽象方法
当子类重写了doGet()和doPost()方法之后,优先会去调用子类重写之后的方法,这么说大家是不是能够明白模板方法模式的使用方式了呢?