Java设计模式之模板方法模式

Java设计模式之模板方法模式

模板方法模式

模板方法模式(Template Method Pattern)是一种行为设计模式,定义了一个算法的骨架,将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

模式概述

模板方法模式的核心思想是:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。这样可以让子类在不改变算法结构的情况下,重新定义算法的某些特定步骤。

模式结构

  1. 抽象类(AbstractClass):定义模板方法和抽象方法

    • 模板方法(templateMethod):定义算法骨架,调用基本方法
    • 基本方法:包括抽象方法、具体方法和钩子方法
  2. 具体类(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 {

// 模板方法,定义算法骨架,声明为final防止子类重写
public final void prepareRecipe() {
boilWater(); // 步骤1:烧水
brew(); // 步骤2:冲泡(抽象方法,子类实现)
pourInCup(); // 步骤3:倒入杯中
addCondiments(); // 步骤4:添加调料(抽象方法,子类实现)
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();
}
/**Output
* === 制作咖啡 ===
* 烧开水
* 冲泡咖啡粉
* 倒入杯中
* 添加糖和牛奶
* 咖啡制作完成,请享用!
*
* === 制作茶 ===
* 烧开水
* 浸泡茶叶
* 倒入杯中
* 添加柠檬
*///~
}

钩子方法的作用

钩子方法是模板方法模式中的一个重要概念,它允许子类对算法的某些步骤进行可选的扩展:

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();

// 钩子方法:默认返回true
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();
}
/**Output
* 初始化棋盘
* 开始下棋
* 第 1 回合
* 第 2 回合
* 第 3 回合
* 游戏结束
*///~
}

模板方法模式的优缺点

优点

  1. 代码复用:将不变的部分封装在父类,可变部分由子类实现
  2. 扩展性好:子类可以通过重写抽象方法扩展功能
  3. 符合开闭原则:对扩展开放,对修改关闭
  4. 控制流程:父类控制算法结构,子类实现具体步骤

缺点

  1. 增加复杂度:增加了类的数量
  2. 可能导致类层次过多:如果抽象方法太多,会增加维护难度
  3. 子类必须实现所有抽象方法:即使某些方法不需要

模板方法模式的应用场景

  1. 算法框架固定:多个类有相似的算法结构,但具体实现不同
  2. 代码复用:提取公共代码到父类中
  3. 控制扩展:希望子类只扩展特定步骤,而不改变整体算法结构
  4. 框架设计:如Spring的Bean生命周期管理

总结

模板方法模式是一种非常实用的设计模式,它通过定义算法骨架并将具体步骤延迟到子类实现,实现了代码复用和扩展。在实际开发中,模板方法模式常用于:

  • 框架设计(如Spring、JUnit等)
  • 标准化流程(如饮料制作、游戏流程等)
  • 代码重构(提取重复代码到父类)

使用模板方法模式时需要注意:

  • 模板方法通常声明为final,防止子类修改算法结构
  • 合理使用钩子方法提供灵活性
  • 抽象方法的设计要合理,避免过多导致类层次复杂

参考资料

发布于

2026-05-16

更新于

2026-05-22

许可协议

评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...