1.模板方法(Template Method)模式的定义
- 它定义一个操作中的算法的框架,而将一些步骤延迟到了子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些步骤。它是一种类行为型模式。
2.模板方法模式的优缺点
优点:
- 良好的封装性。把公有的不变的方法封装在父类,而子类负责实现具体逻辑。
- 良好的扩展性。增加功能由子类实现基本方法扩展,符合单一职责原则和开闭原则。
- 它在父类中提取了公共的部分代码,便于复用代码。
缺点:
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
3.模板方法模式主要角色
3.1 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下:
3.1.1 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
3.1.2 基本方法:是整个算法中的一个步骤,包含以下几种类型:
抽象方法:在抽象类中申明,由具体子类实现。
具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
3.2 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
4.模板方法模式的结构图
5.模板方法模式的实现,以房子构建模板为例
- 定义抽象类:房子构建模板
package com.lw.designpattern.templatemethod; /** * @Classname HouseTemplate * @Description 定义抽象类(房子构建模板): * 负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。 * @Author lw * @Date 2020-01-14 14:18 */ public abstract class HouseTemplate { /** 房子构建模板名称 */ protected String templateName; protected HouseTemplate(String templateName) { this.templateName = templateName; } /** 模板方法则使用protected修饰,表明其需要在子类中实现 */ /** 构建门 */ protected abstract void buildDoor(); /** 构建窗户 */ protected abstract void buildWindow(); /** 构建墙 */ protected abstract void buildWall(); /** 构建基地 */ protected abstract void buildBase(); /** 构建厕所 */ protected abstract void buildToilet(); /** * 钩子方法:给予授权,判断是否要执行 * * @return boolean */ protected boolean isBuildToilet() { return true; } /** * 基本方法:构建房子。用final修饰,保证其不会被子类修改 */ public final void buildHouse() { buildDoor(); buildWindow(); buildWall(); buildBase(); if (isBuildToilet()) { buildToilet(); } } }
- 创建具体子类:房子构建模板one,继承HouseTemplate抽象类
package com.lw.designpattern.templatemethod; /** * @Classname HouseOne * @Description 具体子类房子构建模板one:实现抽象类中所定义的抽象方法和钩子方法 * @Author lw * @Date 2020-01-14 14:37 */ public class HouseOne extends HouseTemplate { /** 是否需要构建厕所标志 */ public boolean isBuildToilet; public HouseOne(String templateName) { super(templateName); } public HouseOne(String templateName, boolean isBuildToilet) { this(templateName); this.isBuildToilet = isBuildToilet; } @Override protected void buildDoor() { System.out.println(templateName +"的门要采用防盗门"); } @Override protected void buildWindow() { System.out.println(templateName + "的窗户要面向北方"); } @Override protected void buildWall() { System.out.println(templateName + "的墙使用大理石建造"); } @Override protected void buildBase() { System.out.println(templateName + "的地基使用钢铁地基"); } @Override protected void buildToilet() { System.out.println(templateName + "的厕所建在东南角"); } @Override protected boolean isBuildToilet() { return isBuildToilet; } }
- 再创建一个具体子类:房子构建模板two,继承HouseTemplate抽象类
package com.lw.designpattern.templatemethod; /** * @Classname HouseTwo * @Description 具体子类房子构建模板two:实现抽象类中所定义的抽象方法和钩子方法 * @Author lw * @Date 2020-01-14 14:37 */ public class HouseTwo extends HouseTemplate { public HouseTwo(String templateName) { super(templateName); } @Override protected void buildDoor() { System.out.println(templateName + "的门采用木门"); } @Override protected void buildWindow() { System.out.println(templateName + "的窗户要向南"); } @Override protected void buildWall() { System.out.println(templateName + "的墙使用玻璃制造"); } @Override protected void buildBase() { System.out.println(templateName + "的地基使用花岗岩"); } @Override protected void buildToilet() { System.out.println(templateName + "的厕所建在西北角"); } }
- 单元测试
/** * 模板方法模式 */ @Test public void testTemplateMethod() { // 创建房子模板对象 HouseTemplate houseOne = new HouseOne("房子模板one", false); HouseTemplate houseTwo = new HouseTwo("房子模板two"); // 房子构建模板 System.out.println("=== 房子模板one,构建模板 ==="); houseOne.buildHouse(); System.out.println("=== 房子模板two,构建模板 ==="); houseTwo.buildHouse(); }
结果打印
通过执行结果我们可以清晰的看到,通过重写钩子方法自定义了房子模板one不需要构建厕所(fasle)。
6.模板方法模式的应用场景
- 在多个子类中拥有相同的方法,而且逻辑相同时,可以将这些方法抽出来放到一个模板抽象类中。
- 程序主框架相同,细节不同的情况下,也可以使用模板方法。