004-行为型-02-模板方法模式(Template Method)
一、概述
定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤
1.1、适用场景
一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现
各子类中公共的行为被提取出来并集中到一个公共父类中,从而避免代码重复
一些方法通用,一些却在每一个子类都重新写了这一方法。
Template Method模式一般应用在具有以下条件的应用中:
1、具有统一的操作步骤或操作过程
2、具有不同的操作细节
3、存在多个具有同样操作步骤的应用场景,但某些具体的操作细节却各不相同
1.2、优缺点
优点:
- 提高复用性,提取公共代码,便于维护
- 提高扩展性
- 符合开闭原则
- 行为由父类控制,子类实现
缺点:
- 类数目增加
- 增加了系统实现的复杂度
- 如果父类添加新的抽象方法,所有子类都要改一遍
注意:为防止恶意操作,一般模板方法都加上 final 关键词。
1.3、类图角色及其职责
模板方法模式的角色和职责
1、AbstractClass:抽象类的父类
2、ConcreteClass:具体的实现子类
3、templateMethod():模板方法,具体步骤方法的执行顺序(步骤)
4、method1()与method2():具体步骤方法(细节)
1.4、演进过程
代码来实现一下:我们举个例子,加入我们要组装汽车,步骤是,先组装车头,再组装车身,最后组装车尾,喷漆,是否需要打蜡
这样,我们先建造AbstractClass(其中包含template模板,执行顺序)
// 组装车(AbstractClass) public abstract class MakeCar { //定义结构里哪些方法是所有过程都是一样的可复用的,哪些是需要子类进行实现的 //组装车头 public abstract void makeCarHead(); //组装车身 public abstract void makeCarBody(); //组装车尾 public abstract void makeCarTail(); //喷漆 都一样 统一实现 public void makeCarPaint() { System.out.println("汽车喷漆"); } //打蜡 public abstract void makeCarDaLa(); //声明一个钩子方法 需要打蜡 由用户确认 是否需要 protected boolean needMakeCarDaLa() { return true; } //汽车组装流程(template()) 用来控制流程 //申明为final,不希望子类覆盖这个方法,防止更改流程的执行顺序 public final void makeCar() { this.makeCarHead(); this.makeCarBody(); this.makeCarTail(); this.makeCarPaint(); // 这里是否需要 交由钩子方法来决定 if (needMakeCarDaLa()) { this.makeCarDaLa(); } } }
再新建ConcreteClass(具体的实现细节)
//组装公交车 public class MakeBus extends MakeCar{ @Override public void makeCarHead() { System.out.println("组装公交车车头"); } @Override public void makeCarBody() { System.out.println("组装公交车车身"); } @Override public void makeCarTail() { System.out.println("组装公交车车尾"); } @Override public void makeCarDaLa() { } @Override protected boolean needMakeCarDaLa() { return false; } }
// 组装SUV public class MakeSuv extends MakeCar{ @Override public void makeCarHead() { System.out.println("组装SUV车头"); } @Override public void makeCarBody() { System.out.println("组装SUV车身"); } @Override public void makeCarTail() { System.out.println("组装SUV车尾"); } @Override public void makeCarDaLa() { System.out.println("组装SUV-打蜡"); } }
测试
@Test public void makeCar() { MakeCar makeBus = new MakeBus(); makeBus.makeCar(); System.out.println("==========================="); MakeCar makeSuv = new MakeSuv(); makeSuv.makeCar(); }
用户不必关心具体的执行流程(步骤)
输出
组装公交车车头 组装公交车车身 组装公交车车尾 汽车喷漆 =========================== 组装SUV车头 组装SUV车身 组装SUV车尾 汽车喷漆 组装SUV-打蜡
二、扩展
spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
jdk:java.util.AbstractList定义一套算法模板,如get(),set()等等,由子类实现。
servlet:javax.servlet.http.HttpServlet定义一套算法模板,如doGet()、doPost()等等,由子类实现。。
mybatis:org.apache.ibatis.executor.BaseExecutor
的