核心思想
- 模板方法模式(Template Method Pattern)是一种行为型设计模式,定义了一个算法的骨架(模板),将某些步骤延迟到子类中实现(在不修改结构的情况下),以避免代码重复,提高代码复用性,保持算法的结构稳定。
- 核心:
-
- 模板方法:在父类中定义一个算法的骨架(即模板方法),其中包含一些抽象方法或钩子方法(hook methods),这些方法由子类实现。
- 不变部分:算法的整体结构是固定的,由父类控制。
- 可变部分:算法的某些步骤可以被子类重写,以实现不同的行为。
编辑
结构
1. 抽象类(Abstract Class)
- 定义算法的骨架(模板方法)。
- 由一个模板方法和若干个基本方法构成。
-
- 模板方法:定义算法骨架,按某种顺序调用其包含的基本方法。
- 基本方法:实现算法各步骤的方法,是模板方法的组成部分,分为三类:
-
-
- 抽象方法:由抽象类声明,具体子类实现。
- 具体方法:一个具体方法由一个抽象类或具体类声明并实现,其子类可以覆盖或继承。
- 钩子方法:抽象类中已实现,包括用于判断的逻辑方法和需要子类重写的空方法。
-
2. 具体子类(Concrete Class)
- 实现抽象类中所定义的抽象方法或钩子方法,是一个顶级逻辑的组成步骤。
编辑
现实世界类比
- 模板方法可用于建造大量房屋。 标准房屋建造方案中可提供几个扩展点, 允许潜在房屋业主调整成品房屋的部分细节。
编辑
- 每个建造步骤 (例如打地基、 建造框架、 建造墙壁和安装水电管线等) 都能进行微调, 这使得成品房屋会略有不同。
适用场景
- 算法复用:当多个类有相似的算法结构,只有某些步骤不同时。
- 框架设计: 框架通常定义算法的股价,而将具体实现留给用户。如何 Spring 中的
JdbcTemplate
定义了数据库操作的流程,用户只需实现具体的 SQL 语句。 - 工作流设计:定义固定的工作流程,但允许某些步骤自定义。
优缺点
优点:
- 代码复用:不变的部分放在子类,避免代码重复。
- 提高扩展性:子类通过实现抽象方法或重写钩子方法类扩展算法的某些步骤。
- 符合开闭原则: 算法整体结构(修改)是封闭的,但具体步骤(扩展)是开放的。
缺点:
- 一定程度违反里氏替换原则:子类重写默认步骤后可能无法替代父类。
- 缺乏灵活性(相比策略模式) :子类必须继承模板。
实现步骤
- 分析目标算法, 确定能否将其分解为多个步骤。 从所有子类的角度出发, 考虑哪些步骤能够通用, 哪些步骤各不相同。
- 创建抽象基类并声明一个模板方法和代表算法步骤的一系列抽象方法。 在模板方法中根据算法结构依次调用相应步骤。 可用
final
最终修饰模板方法以防止子类对其进行重写。 - 虽然可将所有步骤全都设为抽象类型, 但默认实现可能会给部分步骤带来好处, 因为子类无需实现那些方法。
- 可考虑在算法的关键步骤之间添加钩子。
- 为每个算法变体新建一个具体子类, 它必须实现所有的抽象步骤, 也可以重写部分可选步骤。
示例
编辑
// 抽象类(定义模板方法和基本方法)
public abstract class AbstractClass {// 模板方法定义public final void cookProcess(){pourOil();heatOil();pourVegetable();pourSauce();fry();}public void pourOil(){System.out.println("倒油");}public void heatOil(){System.out.println("热油");}public abstract void pourVegetable();public abstract void pourSauce();public void fry(){System.out.println("翻炒");}
}// 具体子类——包菜
public class BaoCai extends AbstractClass{@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是辣椒");}
}// 具体子类——菜心
public class CaiXin extends AbstractClass{@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是蒜蓉");}
}// 客户端
public class Client {public static void main(String[] args) {AbstractClass baoCai = new BaoCai();baoCai.cookProcess();System.out.println("---------------------------------------------");AbstractClass caiXin = new CaiXin();caiXin.cookProcess();}
}
在源码中的应用
编辑
编辑
与其他模式的关系
- 工厂方法模式是模板方法模式的一种特殊形式。 同时, 工 厂 方 法可以作为一个大型模 板 方 法中的一个步骤。
- 模板方法基于继承机制: 它允许你通过扩展子类中的部分内容来改变部分算法。 策略模式基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。 模板方法在类层次上运作, 因此它是静态的。 策略在对象层次上运作, 因此允许在运行时切换行为。