模板方法(Template Method)模式的定义:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式.
其优点有:
- 封装了不变部分,扩展可变部分。
- 在父类中提取了公共的部分代码,便于代码复用。
- 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
模式结构
模板方法模式包含以下主要角色:
- 抽象类:负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
- 具体子类:实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
源码导读
模板方法模式一般以“XXXtemplate”这种方式来命名,像我们所熟知的JdbcTemplate
就是采用模板方法模式设计的。
我们先看不使用JdbcTemplate
是怎么查询的:
try{
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "1234");
String sql = "select nickname,comment,age from users";
statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
List<Users> usersList = new ArrayList<>();
while (resultSet.next()) {
Users users = new Users();
users.setNickname(resultSet.getString(1));
users.setComment(resultSet.getString(2));
users.setAge(resultSet.getInt(3));
usersList.add(users);
}
return usersList;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != statement) {
statement.close();
}
if (null != connection) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return null;
我们执行一次sql总是这样一个流程:加载驱动-》获取连接-》执行sql-》创建一个Statement-》获得返回值。对于这种固定步骤的功能,我们就可以考虑用模板方法模式来实现了。
JDBCTemplate继承了基类JdbcAccessor
和接口类JdbcOperation
。在基类JdbcAccessor
的设计中,对DataSource
数据源进行管理和配置。在JdbcOperation
接口中,定义了通过Jdbc操作数据库的基本操作方法,而JdbcTemplate
提供这些接口方法的实现,比如execute方法、query方法、update方法等。
在jdbcTemplate
的核心方法是execute
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt = null;
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
stmt = conToUse.createStatement();
applyStatementSettings(stmt);
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}
T result = action.doInStatement(stmtToUse); // 回调
handleWarnings(stmt);
return result;
}
catch (SQLException ex) {
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
在模板方法模式中,类的方法被划分为这几类:模板方法(定义了算法的骨架,按某种顺序调用其包含的基本方法),基本方法(包括抽象方法,具体方法,钩子方法)
这个execute
便是它的模板方法了。而getDataSource()
便是在父类中已经实现的基本方法。