模板方法模式
模板方法模式(Template Method Pattern)是一种行为设计模式,定义了一个算法的骨架,将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模式概述
模板方法模式的核心思想是:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。这样可以让子类在不改变算法结构的情况下,重新定义算法的某些特定步骤。
模式结构
抽象类(AbstractClass):定义模板方法和抽象方法
- 模板方法(templateMethod):定义算法骨架,调用基本方法
- 基本方法:包括抽象方法、具体方法和钩子方法
具体类(ConcreteClass):实现抽象类中的抽象方法,完成具体的算法步骤
UML结构图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ┌─────────────────────┐ │ AbstractClass │ │ (抽象类) │ ├─────────────────────┤ │ + templateMethod() │ ← 模板方法,定义算法骨架 │ # abstractMethod() │ ← 抽象方法,子类实现 │ # hookMethod() │ ← 钩子方法,可选重写 │ + concreteMethod() │ ← 具体方法,父类实现 └──────────┬──────────┘ │ 继承 ┌──────────┼──────────┬──────────┐ ▼ ▼ ▼ ▼ ┌─────────────┐┌─────────────┐┌─────────────┐┌─────────────┐ │ConcreteClass││ConcreteClass││ConcreteClass││ConcreteClass│ │ (具体类) ││ (具体类) ││ (具体类) ││ (具体类) │ ├─────────────┤├─────────────┤├─────────────┤├─────────────┤ │+abstractMeth││+abstractMeth││+abstractMeth││+abstractMeth│ │ od() ││ od() ││ od() ││ od() │ └─────────────┘└─────────────┘└─────────────┘└─────────────┘
|
模板方法模式的实现
示例:饮料制作流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| public abstract class Beverage { public final void prepareRecipe() { boilWater(); brew(); pourInCup(); addCondiments(); hookMethod(); } protected abstract void brew(); protected abstract void addCondiments(); private void boilWater() { System.out.println("烧开水"); } private void pourInCup() { System.out.println("倒入杯中"); } protected void hookMethod() { } }
public class Coffee extends Beverage { @Override protected void brew() { System.out.println("冲泡咖啡粉"); } @Override protected void addCondiments() { System.out.println("添加糖和牛奶"); } @Override protected void hookMethod() { System.out.println("咖啡制作完成,请享用!"); } }
public class Tea extends Beverage { @Override protected void brew() { System.out.println("浸泡茶叶"); } @Override protected void addCondiments() { System.out.println("添加柠檬"); } }
public class BeverageTest { public static void main(String[] args) { System.out.println("=== 制作咖啡 ==="); Beverage coffee = new Coffee(); coffee.prepareRecipe(); System.out.println("\n=== 制作茶 ==="); Beverage tea = new Tea(); tea.prepareRecipe(); }
}
|
钩子方法的作用
钩子方法是模板方法模式中的一个重要概念,它允许子类对算法的某些步骤进行可选的扩展:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| public abstract class Game { public final void play() { initialize(); startPlay(); while (continuePlay()) { playRound(); } endPlay(); } protected abstract void initialize(); protected abstract void startPlay(); protected abstract void playRound(); protected abstract void endPlay(); protected boolean continuePlay() { return true; } }
public class Chess extends Game { private int currentRound = 0; private static final int MAX_ROUNDS = 3; @Override protected void initialize() { System.out.println("初始化棋盘"); } @Override protected void startPlay() { System.out.println("开始下棋"); } @Override protected void playRound() { currentRound++; System.out.println("第 " + currentRound + " 回合"); } @Override protected void endPlay() { System.out.println("游戏结束"); } @Override protected boolean continuePlay() { return currentRound < MAX_ROUNDS; } }
public class GameTest { public static void main(String[] args) { Game chess = new Chess(); chess.play(); }
}
|
模板方法模式的优缺点
优点
- 代码复用:将不变的部分封装在父类,可变部分由子类实现
- 扩展性好:子类可以通过重写抽象方法扩展功能
- 符合开闭原则:对扩展开放,对修改关闭
- 控制流程:父类控制算法结构,子类实现具体步骤
缺点
- 增加复杂度:增加了类的数量
- 可能导致类层次过多:如果抽象方法太多,会增加维护难度
- 子类必须实现所有抽象方法:即使某些方法不需要
模板方法模式的应用场景
- 算法框架固定:多个类有相似的算法结构,但具体实现不同
- 代码复用:提取公共代码到父类中
- 控制扩展:希望子类只扩展特定步骤,而不改变整体算法结构
- 框架设计:如Spring的Bean生命周期管理
总结
模板方法模式是一种非常实用的设计模式,它通过定义算法骨架并将具体步骤延迟到子类实现,实现了代码复用和扩展。在实际开发中,模板方法模式常用于:
- 框架设计(如Spring、JUnit等)
- 标准化流程(如饮料制作、游戏流程等)
- 代码重构(提取重复代码到父类)
使用模板方法模式时需要注意:
- 模板方法通常声明为final,防止子类修改算法结构
- 合理使用钩子方法提供灵活性
- 抽象方法的设计要合理,避免过多导致类层次复杂
参考资料