一. 定义与类型
定义:定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤
类型:行为型。
二. 使用场景
(1) 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现
(2) 各子类中公共的行为被提取出来并集中到一个公共父类中,从而避免代码重复
三. 优缺点
优点:
(1) 提高复用性,将相同部分的代码,放入抽象父类中
(2) 提高扩展性
(3) 符合开闭原则
缺点:
(1) 类数目增加
(2) 增加了系统实现的复杂度
(3) 继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍
四. 模板方法—扩展
钩子方法
五. 相关设计模式
模板方法模式和工厂方法模式
工厂方法是模板方法的一种特殊实现
模板方法模式和策略模式
它们都有封装算法,策略模式的目的是使不同的算法可以相互替换,并且不影响应用层客户端的使用;而模板方法模式是针对一个定义算法的流程而将一些不太一样的,具体实现步骤交给子类来实现。模板方法是不改变算法的流程,而策略模式是可以改变的,有大量的if-else时,就可以考虑是否使用策略模式
六. Coding
模板方法模式其实非常简单,直接看下面的代码
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-13 14:50 **/ public abstract class ACourse { //不希望子类覆盖这个方法,防止修改方法里面的录制课程流程的执行顺序 protected final void makeCourse() { this.makePPT(); this.makeVide0(); if (needWriteArticle()) { this.writeArticle(); } this.packageCourse(); } final void makePPT() { System.out.println("制作PPT"); } final void makeVide0() { System.out.println("制作视频"); } final void writeArticle() { System.out.println("编写手记"); } //钩子方法 protected boolean needWriteArticle() { return false; } abstract void packageCourse(); }
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-13 14:55 **/ public class DesignPatternCourse extends ACourse { void packageCourse() { System.out.println("提供课程java源代码"); } @Override protected boolean needWriteArticle() { return true; } }
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-13 14:56 **/ public class FECourse extends ACourse { private boolean needWriteArticleFlag = false; void packageCourse() { System.out.println("提供课程的前端代码"); System.out.println("提供课程的图片等多媒体素材等"); } //这样的写法是为了满足不同的前端课程,可能jquery需要写手记,而html/css不需要写 public FECourse(boolean needWriteArticleFlag) { this.needWriteArticleFlag = needWriteArticleFlag; } @Override protected boolean needWriteArticle() { return this.needWriteArticleFlag; } }
/** * @program: designModel * @description: * @author: YuKai Fan * @create: 2019-02-13 14:57 **/ public class Test { public static void main(String[] args) { System.out.println("后端设计模式课程start---"); ACourse designPatternCourse = new DesignPatternCourse(); //这里涉及到的钩子方法,其实是子类重写父类方法的一些基础规则,子类调用父类的方法,如果是被重写的,那调用的其实是子类重写过后的方法 //也就是说,子类重写了父类的needWriteArticle()方法,在调用父类的makeCourse()时,调用了needWriteArticle()其实是子类重写的方法,也就是返回了true designPatternCourse.makeCourse(); System.out.println("后端设计模式课程end---"); System.out.println("前端课程start---"); ACourse feCourse = new FECourse(false); feCourse.makeCourse(); System.out.println("前端课程end---"); } }
具体的步骤注释都已经写在了代码中。
七. 源码分析
JDK中AbstractList,AbstractSet,AbstractMap类使用了模板方法模式
Servlet中的HttpServlet,doGet,doPost,service方法都是使用了模板方法
Mybatis中的BaseExecutor类也是采用了模板方法