•模板模式(Template),顾名思义,类似于一种格式,相似的框架,不同的个性化。
定义:父类定义了一个流程框架,流程框架中的方法有普通方法和抽象方法。这些抽象方法可以延迟到子类实现,总结起来就是子类实现了流程中的个性化。
•角色组成
①抽象模板(Abstract Template):
1.给出一个逻辑流程的完整框架方法,流程中的方法可以是具体方法或抽象方法,实现一个业务或算法逻辑。
2.定义流程框架中的抽象方法,待子类实现。
/**
* 定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。
* 思想:主框架相同,细节不同。
* 和策略模式的不同点:策略模式就是定义算法族, 然后通过组合算法族和委托的办法来实现类, 模板方法则是父类定义算法的骨架,子类再来实现骨架中的部分步骤。
* 抽象模板(Abstract Template):
* ①给出一个逻辑流程的完整框架方法,流程中的方法可以是具体方法或抽象方法,实现一个业务或算法逻辑。
* ②定义流程框架中的抽象方法,待子类实现。
* @author btp
*
*/
public abstract class FrameWork {
/*
* 模板方法:搭建逻辑框架,比如业务流程,一般修饰为final,防止子类的重写
*/
public final void LogicFrameWork(){
//完整的逻辑流程
regularStep1();
if(doJudge()){
regularStep2();
}
variableStep1();
variableStep2();
}
/*
* 普通方法:逻辑框架中的固定步骤,一般子类最好不建议重写这部分的方法,代表了流程中的固定部分。
*/
void regularStep1(){
System.out.println("FrameWork.regularStep1()");
}
void regularStep2(){
System.out.println("FrameWork.regularStep2()");
}
/*
* 钩子方法(Hook Method):一般提供空实现,子类去拓展,从而达到影响逻辑的效果。
*/
boolean doJudge(){
return false;
}
/*
* 抽象方法:逻辑框架中的可变步骤,交由子类实现
*/
abstract void variableStep1();
abstract void variableStep2();
}
②具体模板(Concrete Template):
实现流程骨架中的可变部分。且可通过钩子方法影响 流程。
/**
* 具体模板A:实现流程骨架中的可变部分。且可通过钩子方法影响 流程。
* @author btp
*
*/
public class ConcreteTemplateA extends FrameWork{
/*
* 具体方法:实现了父类的抽象方法,为抽象方法提供具体实现。
* @see Template.FrameWork#variableStep1()
*/
@Override
void variableStep1() {
System.out.println("A.variableStep1()");
}
@Override
void variableStep2() {
System.out.println("A.variableStep2()");
}
/*
* 钩子方法重写:影响流程骨架
*/
boolean doJudge(){
return true;
}
}
/**
* 具体模板B:实现流程骨架中的可变部分。且可通过钩子方法影响 流程。
* @author btp
*
*/
public class ConcreteTemplateB extends FrameWork{
/*
* 具体方法:实现了父类的抽象方法,为抽象方法提供具体实现。
* @see Template.FrameWork#variableStep1()
*/
@Override
void variableStep1() {
System.out.println("B.variableStep1()");
}
@Override
void variableStep2() {
System.out.println("B.variableStep2()");
}
//不重写钩子方法...
}
•抽象模板中的方法:
① 模板方法:搭建逻辑框架,比如业务流程,一般修饰为final,防止子类的重写。
② 普通方法:逻辑框架中的固定步骤,一般子类最好不建议重写这部分的方法,代表了流程中的固定部分。
③ 钩子方法(Hook Method):一般提供空实现,子类去拓展,从而达到影响逻辑的效果。
④ 抽象方法:逻辑框架中的可变步骤,交由子类实现。
•模板模式的步骤:
①定义一个抽象模板类,抽象类中定义一组抽象方法、普通方法和钩子方法。
②抽象模板类类使用①中定义的各种方法实现一个模板方法,定义大致的框架流程。
③子类继承抽象模板类,并实现抽象模板类中的抽象方法,也可通过复写钩子方法来改变抽象模板类的模板方法的流程。
•模板方法的优点:
①减少了大量的重复代码,比如JDBC。
②助于算法的扩展。
③“开放-封闭原则”
•模板方法的缺点:
①类的数量会大大增加。
•一个Demo:
/**
* 模板模式是对多态、继承和复写的良好的应用。模板代码一方面将一些方法延迟到子类中实现,有助于算法的拓展,一方面也省去了大量的重复代码。
* 就比如我们去填个表格,表格的格式都是固定的,你只需要往里面填写内容即可,不需要每次去银行还要自己画个表格再填。
* 模板模式减少了代码的繁琐程度,利于coder把注意力集中在代码的可变部分。总不能去吃饭还要建个食堂。
* “开放-闭合原则”
*
* 下面是一个例子,关于招聘的例子。招聘的流程大致相同,只不过可能不同岗位的应聘会少许不同。
* @author btp
*
*/
public class TemplateTest {
public static void main(String[] args) {
RecruitProcess recruit = new GoodJavaRecruit();
recruit.RecruitProcesses();
System.out.println("---------------------------");
recruit = new BadJavaRecruit();
recruit.RecruitProcesses();
System.out.println("---------------------------");
recruit = new GreatTestEngineerRecruit();
recruit.RecruitProcesses();
System.out.println("---------------------------");
}
}
abstract class RecruitProcess{
/*
* 从一个公司的角度来看招聘的大致流程
*/
public final void RecruitProcesses(){
//发布招聘信息
releaseRecruitInformation();
//筛选简历
screenResume();
if(resumeQualified()){
//简历通过打电话预约笔试
appointmentForWTest();
//应聘者笔试
writtenExam();
if(goodWwrittenExam()){
//笔试合格
//笔试通过之后面试
interview();
if(goodInterview()){
//面试通过邮件发送录取信息
emailForSuccess();
}else{
//面试不合格通知面试者
emailForFail();
}
}else{
//笔试不合格通知面试者
emailForFail();
}
}else{
//简历不合格通知面试者
emailForFail();
}
}
/*
* 公司发布招聘信息
*/
void releaseRecruitInformation(){
System.out.println("--在拉勾网上发布招聘信息--");
}
/*
* 筛选简历
*/
void screenResume(){
System.out.println("--简历筛选,挑选符合条件的简历--");
}
/*
* 钩子方法:影响流程,简历是否合格
* 默认合格返回true
*/
boolean resumeQualified(){
return true;
}
/*
* 打电话给应聘者预约笔试
*/
void appointmentForWTest(){
System.out.println("--打电话给招聘者预约笔试--");
}
/*
* 应聘者笔试:延迟给应聘者实现
*/
abstract void writtenExam();
/*
* 钩子方法:影响流程,笔试是否合格
* 默认合格返回true
*/
boolean goodWwrittenExam(){
return true;
}
/*
* 应聘者面试:延迟给应聘者实现
*/
abstract void interview();
/*
* 钩子方法:影响流程,面试是否合格
* 默认合格返回true
*/
boolean goodInterview(){
return true;
}
/*
* 邮件通知应聘者成功录取
*/
void emailForSuccess(){
System.out.println("--恭喜您被我司录取!--");
}
/*
* 邮件通知应聘out
*/
void emailForFail(){
System.out.println("--很遗憾您不符合我司的要求,期待下次合作!!--");
}
}
/**
* 招聘java工程师
* @author btp
*
*/
class GoodJavaRecruit extends RecruitProcess{
//java工程师的简历不错:性别男,爱好女。简历筛选通过。
/*
* java笔试
* @see Template.RecruitProcess#writtenExam()
*/
@Override
void writtenExam() {
System.out.println("大牛做Java笔试:万物皆是对象,还是找不到对象...");
}
/*
* java面试
* @see Template.RecruitProcess#interview()
*/
@Override
void interview() {
System.out.println("大牛进行Java面试:侃侃而谈,无所不知,就是不知道对象在哪...");
}
}
class BadJavaRecruit extends RecruitProcess{
//java工程师的简历勉强可以:本科生,无对象,无爱好。
/*
* java笔试
* @see Template.RecruitProcess#writtenExam()
*/
@Override
void writtenExam() {
System.out.println("小菜做Java笔试:万物皆是对象,不知道怎么销毁对象和回收空间...");
}
/*
* java面试
* @see Template.RecruitProcess#interview()
*/
@Override
void interview() {
System.out.println("小菜进行Java面试:我不是coder,我只是bug的搬运工...");
}
/*
* 钩子方法:影响流程,笔试是否合格
* 默认合格返回true
*/
boolean goodWwrittenExam(){
System.out.println("--笔试不合格--");
return false;
}
}
/**
* 测试工程师招聘
*/
class GreatTestEngineerRecruit extends RecruitProcess{
//测试工程师工程师的简历:什么bug在我眼中都是HelloKitty
/*
* 测试笔试
* @see Template.RecruitProcess#writtenExam()
*/
@Override
void writtenExam() {
System.out.println("测试之神做测试笔试:一切在我缜密的逻辑之下无所遁形...");
}
/*
* 测试面试
* @see Template.RecruitProcess#interview()
*/
@Override
void interview() {
System.out.println("测试之神进行测试面试:什么linux,什么sql,空气中充满了活跃的气氛...");
}
}