文章目录
一、模板方法模式
模板方法模式(Template Method Pattern)是一种行为设计模式,它在一个方法中定义了一个算法的骨架,而将一些步骤的实现延迟到子类中。通过这种方式,模板方法模式可以将步骤的执行顺序控制在父类中,同时允许子类覆盖特定步骤的实现以满足具体需要。
1、结构
- 抽象类(Abstract Class):定义算法的结构,并包含一个或多个模板方法。模板方法规定了算法的骨架,并且会调用一个或多个抽象方法(hook 方法)来完成一些具体步骤,这些抽象方法将在子类中实现。
- 具体子类(Concrete Class):实现抽象类中的抽象方法,从而完成具体的步骤。通过覆盖抽象方法,具体子类可以提供不同的实现细节。
2、特性
- 固定算法结构:模板方法通过定义算法的骨架,确保算法的固定执行顺序。
- 可扩展步骤:子类可以覆盖父类中定义的抽象方法,从而扩展或修改某些步骤,而不影响整体算法的结构。
- 不可变模板方法:模板方法通常使用 final 修饰,这样子类就不能重写这个方法,从而保证了算法骨架的稳定性。
3、优缺点
3.1、优点
- 代码复用:通过在抽象类中定义公用的算法结构,可以减少代码重复,提高代码复用性。
- 灵活性和可扩展性:子类可以根据具体需求覆盖抽象方法,从而实现不同的具体行为,这提高了系统的灵活性和可扩展性。
- 控制反转:模板方法模式实现了一种变相的控制反转,由父类调用子类实现的具体方法,减少了子类对父类的依赖。
3.2、缺点
- 过度设计:如果算法步骤很简单或变化不大,使用模板方法模式可能导致过度设计,引入不必要的复杂性。
- 实现不直观:模板方法模式涉及继承和多态,对某些人来说可能不是特别直观,需要详细文档说明才能正确理解和使用。
4、使用场景
- 多个子类有公有的方法且逻辑基本相同时:比如多个游戏类的初始化、开始、结束步骤相同,但具体实现细节不同。
- 重要、复杂的算法可以由几个步骤抽象与具体实现:比如在数据分析或格式转换中,整体流程固定但细节不同。
- 希望子类能够灵活替换算法的某些部分时:通过让子类实现父类中的抽象方法,可以灵活变更算法的一部分实现。
5、实现示例
5.1、抽象类
public abstract class Game {
// 模板方法定义了游戏的骨架,不可重写
public final void play() {
initialize();
startPlay();
endPlay();
}
// 基本方法:抽象方法,必须由子类实现
protected abstract void initialize();
// 基本方法:抽象方法,必须由子类实现
protected abstract void startPlay();
// 基本方法:抽象方法,必须由子类实现
protected abstract void endPlay();
}
5.2、实现类
Cricket
public class Cricket extends Game {
@Override
protected void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
protected void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
@Override
protected void endPlay() {
System.out.println("Cricket Game Finished!");
}
}
Football
public class Football extends Game {
@Override
protected void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
protected void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
@Override
protected void endPlay() {
System.out.println("Football Game Finished!");
}
}
5.3、测试类
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
game = new Football();
game.play();
}
}
结果
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!
Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!
二、JdbcTemplate
JdbcTemplate 简化了 JDBC 操作,通过模板方法封装了资源的获取与释放、语句的执行、结果集的处理等重复性工作。这使得开发人员可以专注于 SQL 语句和结果集的处理逻辑。
1、结构
- 模板方法:JdbcTemplate 定义了一个模板方法 execute,这个方法中包含了获取数据库连接、创建 SQL 语句、执行 SQL、处理结果集、释放资源的各个步骤。
- 回调接口:Spring 提供了各种回调接口,让用户实现具体操作,比如 PreparedStatementCallback、ResultSetExtractor 等,从而避免直接操作 JDBC API。
2、模板方法
2.1、execute
JdbcTemplate 的 execute 方法是一个典型的模板方法,它提供了一个贯穿数据操作的整体框架
public int update(final String sql) throws DataAccessException {
return execute(new PreparedStatementCallback<Integer>() {
@Override
public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException {
return ps.executeUpdate();
}
});
}
在这个例子中,PreparedStatementCallback 是一个回调接口,用户需要实现其 doInPreparedStatement 方法。JdbcTemplate 在内部会处理连接的获取、SQL 语句的准备、资源的关闭等操作。
2.2、query
query 方法用于执行 SELECT 语句,并通过回调接口处理结果集
public <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
List<T> results = query(sql, args, new RowMapperResultSetExtractor<>(rowMapper, 1));
return DataAccessUtils.requiredSingleResult(results);
}
3、回调接口
3.1、PreparedStatementCreator 和 PreparedStatementCallback
- PreparedStatementCreator 用于创建 PreparedStatement。
- PreparedStatementCallback 用于执行 SQL 并处理结果。
private String sql = "INSERT INTO users (name) VALUES (?)";
public void excuteSql(String sql){
jdbcTemplate.execute(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
return con.prepareStatement(sql);
}
}, new PreparedStatementCallback<Boolean>() {
@Override
public Boolean doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
ps.setString(1, "Allen");
return ps.executeUpdate() > 0;
}
});
}
3.2、RowMapper
RowMapper 是一个常用的回调接口,用于将结果集的每一行映射为一个 Java 对象。
public class UserRowMapper implements RowMapper<User> {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
return user;
}
}
// 使用 RowMapper 查询列表
List<User> users = jdbcTemplate.query("SELECT id, name FROM users", new UserRowMapper());
4、优点
-
资源管理:
JdbcTemplate 自动管理数据库连接、语句、结果集等资源,避免资源泄漏问题。 -
异常处理:
JdbcTemplate 将检查异常转换为未经检查的 Spring DataAccessException 层次结构,从而简化了异常处理。 -
可测试性:
通过 JdbcTemplate 进行数据库操作的代码更容易进行单元测试,因为可以通过依赖注入来注入 DataSource 或 Mock 数据库连接。