Java设计模式—模板方法模式
发表于更新于
字数总计:927阅读时长:3分钟 上海
模板方法模式(Template Method Pattern)
模板方法模式是一种行为型设计模式,在父类中定义算法的骨架,将某些步骤延迟到子类中实现。
一、模式概述
1.1 定义
模板方法模式:在一个方法中定义算法的骨架,将某些步骤的实现延迟到子类。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。
1.2 适用场景
- 多个子类有共同的行为逻辑,只是某些步骤实现不同
- 需要控制子类扩展的范围
- 一次性实现算法的不变部分,可变部分留给子类
1.3 UML 类图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| +------------------------+ | AbstractDisplay | ← 抽象父类 +------------------------+ | + display(): void | ← 模板方法(final) | # open(): void | ← 抽象方法 | # print(): void | ← 抽象方法 | # close(): void | ← 抽象方法 +------------------------+ △ | +------+------+ | | +--------+ +-----------+ |CharDisplay| |StringDisplay| ← 具体子类 +--------+ +-----------+
|
1.4 核心角色
| 角色 | 说明 |
|---|
| AbstractClass | 抽象类,定义模板方法和抽象步骤 |
| ConcreteClass | 具体类,实现抽象步骤 |
| 模板方法 | 定义算法骨架,通常用 final 修饰防止重写 |
| 钩子方法 | 可选,提供默认实现,子类可选择性覆盖 |
二、代码实现
2.1 首先创建抽象父类 AbstractDisplay
父类中定义了三个方法,用于输出字符串
1 2 3 4 5 6 7 8 9 10 11 12 13
| public abstract class AbstractDisplay { public abstract void open(); public abstract void print(); public abstract void close();
public final void display() { open(); for (int i = 0; i < 5; i++) { print(); } close(); } }
|
1.2 创建子类CharDisplay
使子类继承AbstractDisplay类,重写父类的三个抽象方法
重写的方法将以特定的格式输出字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class CharDisplay extends AbstractDisplay { private char aChar;
public CharDisplay(char aChar) { this.aChar = aChar; }
@Override public void open() { System.out.print("<<"); }
@Override public void print() { System.out.print(aChar); }
@Override public void close() { System.out.println(">>"); } }
|
1.3 创建子类StringDisplay
同样的继承AbstractDisplay,并重写抽象方法
width属性用于记录字符串长度,再同样以特定形式输出
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
| public class StringDisplay extends AbstractDisplay { private String string; private int width;
public StringDisplay(String string) { this.string = string; this.width = string.getBytes().length; }
@Override public void open() { printLine(); }
@Override public void print() { System.out.println("|" + string + "|"); }
@Override public void close() { printLine(); }
private void printLine() { System.out.print("+"); for (int i = 0; i < width; i++) { System.out.print("-"); } System.out.println("+"); } }
|
1.4 测试代码
1 2 3 4 5 6 7 8 9 10 11 12
| public class RunMain { public static void main(String[] args) { AbstractDisplay display = new CharDisplay('H'); display.display();
AbstractDisplay display1 = new StringDisplay("Hello World."); display1.display();
AbstractDisplay display2 = new StringDisplay("你好,世界。"); display2.display(); } }
|
三、模式分析
3.1 优缺点
| 优点 | 缺点 |
|---|
| 封装不变部分,扩展可变部分 | 类数目增加 |
| 提取公共代码,便于维护 | 增加系统复杂度 |
| 行为由父类控制,子类实现 | 子类执行结果影响父类 |
3.2 实际应用
- Spring 中的 JdbcTemplate:定义了执行 SQL 的模板流程
- Servlet 中的 HttpServlet:
service() 方法调用 doGet()、doPost() - JUC 中的 AQS:
acquire() 调用 tryAcquire()(子类实现)
1 2 3 4 5 6 7 8
| jdbcTemplate.query(sql, new RowMapper<User>() { @Override public User mapRow(ResultSet rs, int rowNum) { return new User(rs.getString("name")); } });
|
四、总结
在模板模式中,父类与子类的相互协作撑起了整个程序。设计时需要注意:
- 抽象方法:必须由子类实现的步骤
- 钩子方法:可选覆盖,提供默认行为
- 模板方法:用
final 修饰,防止子类破坏算法结构
设计原则:好莱坞原则——“Don’t call us, we’ll call you”(别调用我们,我们会调用你)。父类调用子类的方法,而不是子类调用父类。