1. 什么是模版方法?
--算法执行的统一框架,模版方法模式定义了一个操作中的算法骨架,将一些步骤延迟到子类实现,使得子类可以在不改变算法结构的同时就重新定义该算法的某些特定步骤。
----Step1、Step2、....Step n
2.
模板方法(使用抽象父类定义框架)
抽象父类,为所有子类提供一个算法框架
步骤:
(1)、定义一个公共的抽象父类
(2)、定义一个公共 final 的方法(封装所有子类都要遵循的算法框架)
(3)、算法框架中定义的方法子类实现相同的使用 private 修饰该方法并且实现,子类实现方法不一样的使用 protected abstact 修饰该方法并且不实现
(4)、让子类重写父类未实现的方法,实现各自的方法
(5)、在调用的实例对象采用 父类 实例名 = new 子类,在直接调用遵循的框架方法
例子1:
/*抽象父类,为所有子类提供一个算法框架 * step 1: 进门取号 * step 2: 填写单据 * step 3: 等待叫号 * step 4: 窗口办理 * */ public abstract class Template { //定义一个公共 final 的方法(封装所有子类都要遵循的算法框架) public final void prepareTemplate() { //进门取号 takeNum(); //填写单据 writeDoc(); //等待叫号 waitCallNum(); //窗口办理 handle(); } //算法框架中定义的方法子类实现相同的使用 private 修饰该方法并且实现 private void takeNum() { System.out.println("进门取号"); } private void waitCallNum() { System.out.println("等待叫号"); } //子类实现方法不一样的使用 protected abstact 修饰该方法并且不实现 protected abstract void writeDoc(); protected abstract void handle(); }
public class Example extends Template{ @Override protected void writeDoc() { // TODO Auto-generated method stub System.out.println("填写存款单据"); } @Override protected void handle() { // TODO Auto-generated method stub System.out.println("处理存款"); } }
public class Example2 extends Template{ @Override protected void writeDoc() { // TODO Auto-generated method stub System.out.println("填写转账单据"); } @Override protected void handle() { // TODO Auto-generated method stub System.out.println("处理转账"); } }
测试:
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub Template template = new Example(); template.prepareTemplate(); System.out.println("-------------------"); template = new Example2(); template.prepareTemplate(); } }
输出结果:
进门取号 填写存款单据 等待叫号 处理存款 ------------------- 进门取号 填写转账单据 等待叫号 处理转账
3.可以使用钩子方法使模版方法模式更加灵活
用钩子函数实现子类对算法框架个性化的扩展(简单来说就是通过钩子动态添加步骤)
思想
(1)、框架通过提供一个个的钩子,使框架具备了更大的灵活性。不想执行算法框架中的某些个步骤,我们可以脱钩,如果想执行的话,我们可以挂钩。
实现
(2)、在抽象类中,提供protected钩子方法。这是个实现的或空的方法。这样子类就可以选择覆写-持钩,也可以选择不覆写-脱勾。
使用
(3)、提供一个isXXX类型的钩子方法。用该方法控制算法框架中
某个步骤是否执行
(4)、子类不覆写这个方法,就是脱钩,仍按框架逻辑执行,一旦覆写,就是挂钩,将改变框架算法方向,按子类逻辑执行。
例子2:
/*抽象父类,为所有子类提供一个算法框架 * step 1: 进门取号 * step 2: 填写单据 * step 3: 等待叫号 * step 4: 窗口办理 * step 5: 是否需要转到专门窗口办理(根据用户选择) * */ public abstract class Template { //定义一个公共 final 的方法(封装所有子类都要遵循的算法框架) public final void prepareTemplate() { //进门取号 takeNum(); //填写单据 writeDoc(); //等待叫号 waitCallNum(); //窗口办理 handle(); if(isHandleAgain()) { handle(); } } //算法框架中定义的方法子类实现相同的使用 private 修饰该方法并且实现 private void takeNum() { System.out.println("进门取号"); } private void waitCallNum() { System.out.println("等待叫号"); } //子类实现方法不一样的使用 protected abstact 修饰该方法并且不实现 protected abstract void writeDoc(); protected abstract void handle(); /* * Hook, 钩子函数,提供一个默认或空的实现 * 具体的子类可以自行决定是否挂钩以及如何挂钩 * 询问用户是否加入调料 */ protected boolean isHandleAgain() { return false; } }
public class Example3 extends Template{ @Override protected void writeDoc() { // TODO Auto-generated method stub System.out.println("填写单据1,2"); } @Override protected void handle() { // TODO Auto-generated method stub System.out.println("处理单据"); } //需要挂钩 @Override protected boolean isHandleAgain() { // TODO Auto-generated method stub return true; } }
测试:
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub Template template = new Example(); template.prepareTemplate(); System.out.println("-------------------"); template = new Example2(); template.prepareTemplate(); System.out.println("-------------------"); template = new Example3(); template.prepareTemplate(); } }
输出结果:
进门取号 填写存款单据 等待叫号 处理存款 ------------------- 进门取号 填写转账单据 等待叫号 处理转账 ------------------- 进门取号 填写单据1,2 等待叫号 处理单据 处理单据
5. 总结
模版方法模式
适用场景:
A、算法或者操作遵循相似的逻辑
B、重构时(把相同的代码抽取到父类中)
C、重要、复杂的算法,核心算法设计为模板算法
优点:
A、封装性好
B、复用性好
C、屏蔽细节
D、便于维护
缺点:继承