模板方法模式 (Template Method Pattern)
定义一个操作中的算法骨架,而将一些步骤延迟到子类中
模式定义
模板方法模式是一种行为型设计模式,它定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。模板方法模式通过把不变行为搬移到父类,去除子类中的重复代码来体现其优势。
模式结构
graph TD
A[AbstractClass] --> B[ConcreteClass]
A --> C[ConcreteClass]
实现方式
基础实现
定义抽象类,实现具体子类。
// 抽象类
public abstract class Beverage {
// 模板方法,定义算法骨架
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 共同方法
void boilWater() {
System.out.println("煮沸水");
}
// 抽象方法,由子类实现
abstract void brew();
void pourInCup() {
System.out.println("倒入杯中");
}
// 抽象方法,由子类实现
abstract void addCondiments();
}
// 具体子类 - 咖啡
class Coffee extends Beverage {
@Override
void brew() {
System.out.println("用沸水冲泡咖啡粉");
}
@Override
void addCondiments() {
System.out.println("加糖和牛奶");
}
}
// 具体子类 - 茶
class Tea extends Beverage {
@Override
void brew() {
System.out.println("用沸水浸泡茶叶");
}
@Override
void addCondiments() {
System.out.println("加柠檬");
}
}
使用示例
public class TemplateMethodPatternDemo {
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. Java Servlet API
Java Servlet中的doGet和 doPost方法是模板方法模式的经典应用:
public class MyServlet extends HttpServlet {
// 模板方法模式:service方法定义了处理请求的算法骨架
// doGet和doPost是具体步骤的实现
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 处理GET请求的具体实现
response.getWriter().println("处理GET请求");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 处理POST请求的具体实现
response.getWriter().println("处理POST请求");
}
// 父类HttpServlet中的service方法(模板方法)类似于:
// protected void service(HttpServletRequest req, HttpServletResponse res) {
// String method = req.getMethod();
// if ("GET".equals(method)) {
// doGet(req, res);
// } else if ("POST".equals(method)) {
// doPost(req, res);
// }
// }
}
2. Android Activity生命周期
Android开发中Activity的生命周期方法也是模板方法模式的应用:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// onCreate是模板方法中的一部分
}
@Override
protected void onStart() {
super.onStart();
// onStart是模板方法中的一部分
}
@Override
protected void onResume() {
super.onResume();
// onResume是模板方法中的一部分
}
// Android框架定义了Activity的生命周期算法骨架
// 开发者只需重写相应的生命周期方法
}
3. Spring框架中的JdbcTemplate
Spring框架中的JdbcTemplate使用模板方法模式简化数据库操作:
public class UserService {
private JdbcTemplate jdbcTemplate;
public User getUserById(int id) {
String sql = "SELECT * FROM users WHERE id = ?";
// query方法是模板方法,定义了数据库查询的算法骨架
// RowMapper是回调接口,由用户实现具体的映射逻辑
return jdbcTemplate.queryForObject(sql, new Object[]{id},
new RowMapper() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
// 具体的映射逻辑由用户实现
return user;
}
});
}
}
应用场景
- 框架设计:框架定义算法骨架,具体实现由用户自定义
- 数据库操作:连接、执行、关闭等步骤的模板化
- 游戏开发:游戏回合的固定流程(初始化、执行、清理)
- Web应用:请求处理流程(解析、验证、处理、响应)
- 测试框架:测试执行流程(初始化、执行测试、清理)
- 构建工具:编译流程(预处理、编译、链接、打包)
优缺点
优点
- 封装不变部分,扩展可变部分:将不变的行为封装在父类中,可变部分由子类实现
- 提取公共代码,便于维护:避免代码重复,提高代码复用性
- 行为由父类控制,子类实现:通过父类调用子类实现,反向控制结构
- 符合开闭原则:增加新的具体实现无需修改现有代码
缺点
- 算法骨架固定:模板方法定义了算法骨架,不易修改
- 可能违反里氏替换原则:子类可能无法完全替换父类
- 增加了代码理解难度:需要在父类和子类之间跳转理解代码