模板方法模式,定义一个操做中算法的骨架,而将一些步骤延迟到子类中。使得子类能够不改变一个算法的结构便可从新定义该算法的某些特定步骤。html
模板方法模式,实际上是很好理解的,具体理解为,定义一个操做中算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类能够不改变一个算法结构便可冲定义该算法的某些特定步骤。模板方法模式是最为常见的设计模式之一,是基于继承的代码复用技术。架构师定义一套骨架,开发工程师按照骨架去实现具体的逻辑。算法
在具体的项目中其实使用模板方法的场景有不少,就举我之间遇到过的一个场景吧,这是一个实际的项目,结合这个项目的中的场景能够引出模板方法模式的使用方法,设计模式
在一个审批流程的项目,会有不少种的申请单,例如:出差申请单、请假申请单、采购申请单、付款申请单等等。每一个申请单在提交的时候都要先校验申请单的参数是否正确,以及在提交成功后去通知审批人,有待审批的单子了。因此说,这个过程都是同样的,只不过是,每一个申请单的校验参数以及通知审批人的方法会有所不一样。那么这样就能够把这个提交的过程定义成一个模板,而后每一个审批单的都按照这个流程来进行提交申请就能够了。架构
具体代码实现以下:框架
流程模板类ide
/** * 流程模板类 */ public abstract class BaseProcess { /** * 提交流程 */ public void submitProcess(Map<String,String> paramMap){ boolean checkResult = checkParameter(paramMap); if(checkResult){ System.out.println("提交流程成功!"); remindApprovers(); }else { System.out.println("提交流程失败!"); } } /** * 校验参数 * @return */ public abstract boolean checkParameter(Map<String,String> paramMap); /** * 提醒审批人 */ public abstract void remindApprovers(); }
差旅审批流程post
/** * 差旅审批流程 * */ public class BusinessTravelProcess extends BaseProcess{ /** * 校验参数 * * @return */ @Override public boolean checkParameter(Map<String,String> paramMap) { if(null!=paramMap.get("result")&¶mMap.get("result").equals("true")){ System.out.println("差旅审批单参数校验成功!"); return true; }else { System.out.println("差旅审批单参数校验失败!"); return false; } } /** * 提醒审批人 */ @Override public void remindApprovers() { System.out.println("有新的差旅申请提交了。"); } }
请假审批流程学习
/** * 请假审批流程 */ public class LeaveApplyProcess extends BaseProcess { /** * 校验参数 * * @return */ @Override public boolean checkParameter(Map<String,String> paramMap) { if(null!=paramMap.get("result")&¶mMap.get("result").equals("true")){ System.out.println("请假审批单参数校验成功!"); return true; }else { System.out.println("请假审批单参数校验成功!"); return false; } } /** * 提醒审批人 */ @Override public void remindApprovers() { System.out.println("有新的请假申请提交了。"); } }
测试类测试
public class Client { public static void main(String[] args) { //建立请假申请单 BaseProcess leaveApply = new LeaveApplyProcess(); Map<String,String> paramMap = Maps.newHashMap(); paramMap.put("result","true"); //提交采购申请单 leaveApply.submitProcess(paramMap); //建立差旅申请单 BaseProcess business = new BusinessTravelProcess(); paramMap = Maps.newHashMap(); paramMap.put("result","false"); //提交差旅申请单 business.submitProcess(paramMap); } }
运行结果url
请假审批单参数校验成功!
提交流程成功!
有新的请假申请提交了。
差旅审批单参数校验失败!
提交流程失败!
上面的这个例子就是使用的模板方法模式,这个场景是一些业务功能,大致框架是固定的,只是一些具体的实现细节可能不一样。用模板方法能提升代码的复用性和系统的灵活性。
下面来分析一下模板方法的具体结构组成,以下是模板方法模式的类图。
模板方法模式中,具体就两个角色。
一、AbstractClass(抽象类):在抽象类中定义了一系列基本操做(PrimitiveOperations),这些基本操做能够是具体的,也能够是抽象的,每个基本操做对应算法的一个步骤,在其子类中能够重定义或实现这些步骤。
二、ConcreteClass(具体子类):它是抽象类的子类,用于实如今父类中声明的抽象基本操做以完成子类特定算法的步骤,也能够覆盖在父类中已经实现的具体基本操做。
可是模板方法模式的实现是离不开这三个方法的
一、基本方法
基本方法也称为基本操做,是由子类实现的方法,而且在模板方法中被调用。
二、模板方法
模板方法能够有一个或几个,通常是一个具体的方法,也就是一个骨架,实现对基本方法的调度,完成固定的逻辑。为了防止恶意的操做,通常模板方法都加上final关键字,不容许被覆写。
三、钩子方法
钩子方法由抽象类声明并加以实现。可是子类能够去扩展,子类能够经过扩展钩子方法,来影响模板方法的逻辑。抽象类的任务是搭建逻辑的框架,一般由经验丰富的人员编写,由于抽象类的好坏直接决定了程序是否稳定。
模板方法模式是基于继承的代码复用技术,它体现了面向对象的诸多重要思想,是一种使用较为频繁的模式。模板方法模式普遍应用于框架设计中,以确保经过父类来控制处理流程的逻辑顺序(如框架的初始化,测试流程的设置等)。
一、在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。
二、模板方法模式是一种代码复用技术,它在类库设计中尤其重要,它提取了类库中的公共行为,将公共行为放在父类中,而经过其子类来实现不一样的行为,它鼓励咱们恰当使用继承来实现代码复用。
三、可实现一种反向控制结构,经过子类覆盖父类的钩子方法来决定某一特定步骤是否须要执行。
四、在模板方法模式中能够经过子类来覆盖父类的基本方法,不一样的子类能够提供基本方法的不一样实现,更换和增长新的子类很方便,符合单一职责原则和开闭原则。
一、须要为每个基本方法的不一样实现提供一个子类,若是父类中可变的基本方法太多,将会致使类的个数增长,系统更加庞大,设计也更加抽象,此时,也可结合桥接模式来进行设计。
二、因为每一个子类的方法会影响到了父类,这里违反了里氏替换原则,会给程序带来风险。
一、对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些能够改变的细节由其子类来实现。
二、各子类中公共的行为应被提取出来并集中到一个公共父类中以免代码重复。
三、须要经过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述。