通常很多需求存在公共的逻辑处理,也存在有差异的部分。我们希望通过提取公共的逻辑部分,减少代码的重复性。
下面通过一个印刷书本的需求来对模板模式进行简单的说明。
BookPrintTemplate.java 模板类
public abstract class BookPrintTemplate{
public void printBook() {
//1.准备纸张
this.preparePage();
//2.书本内容
String content = this.getContent();
//3.印刷书本
this.print(content);
}
public abstract String getContent();
private void preparePage() {
System.out.println("准备纸张");
}
private void print(String content) {
System.out.println(content);
}
}
SanmaoBook.java
public class SanmaoBook extends BookPrintTemplate {
@Override
public String getContent() {
return "<<三毛>>";
}
}
通过继承abstract类,实现abstract方法,提取公共逻辑部分代码,减少重复代码。
很多心细的小伙伴会发现,模板模式跟策略模式非常相似。需要说明的是,站在接口设计者的角度来讲,模板模式更加注重的是定义过程,而策略模式是由设计者定义完成的多种策略,调用者只能选择其中某一种策略进行使用。
JdbcTemplate是典型的模板模式写法,下面我们通过简单实现JdbcTemplate类,来感受一下模板模式的魅力。
RowMapped.java
public interface RowMapped<T> {
public T rowMap(ResultSet resultSet, int rowNum);
}
Order.java
public class Order {
String orderId;
String title;
double price;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
JdbcTemplate.java
public class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
public List<?> select(String sql, RowMapped<?> rowMapped, Object[] values) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try{
connection = this.getConnection();
preparedStatement = this.createPreparedStatement(connection, sql);
resultSet = this.executeQuery(preparedStatement, values);
int i = 0;
List<?> list = this.columnMapped(resultSet, rowMapped, i);
return list;
}catch (Exception e) {
e.printStackTrace();
}finally {
try{
this.closeResultSet(resultSet);
this.closePreparedStatement(preparedStatement);
this.closeConnection(connection);
}catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
private Connection getConnection() throws SQLException {
return this.dataSource.getConnection();
}
private PreparedStatement createPreparedStatement(Connection connection, String sql) throws SQLException {
return connection.prepareStatement(sql);
}
private ResultSet executeQuery(PreparedStatement preState, Object[] values) throws SQLException {
for(int i=0; i<values.length; i++) {
preState.setObject(i+1, values[i]);
}
return preState.executeQuery();
}
private List<?> columnMapped(ResultSet resultSet, RowMapped<?> rowMapped, int rowNum) throws SQLException {
List<Object> list = new ArrayList<>();
while(resultSet.next()) {
Object o = rowMapped.rowMap(resultSet, rowNum);
list.add(o);
}
return list;
}
private void closeResultSet(ResultSet resultSet) throws SQLException {
if(resultSet != null) resultSet.close();
}
private void closePreparedStatement(PreparedStatement preState) throws SQLException {
if(preState != null) preState.close();
}
private void closeConnection(Connection connection) throws SQLException {
if(connection != null) connection.close();
}
}
OrderDao.java
public class OrderDao {
private JdbcTemplate jdbcTemplate;
public OrderDao(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
public List<?> selectAll() {
String sql = "select order_id,title,price from tb_order";
List<?> list = jdbcTemplate.select(sql, new RowMapped<Order>() {
@Override
public Order rowMap(ResultSet resultSet, int rowNum) {
Order order = new Order();
try {
order.setOrderId(resultSet.getString("order_id"));
order.setTitle(resultSet.getString("title"));
order.setPrice(resultSet.getDouble("price"));
} catch (Exception e) {
e.printStackTrace();
}
return order;
}
}, null);
return list;
}
}
测试类
public class OrderTest {
public static void main(String[] args) {
OrderDao orderDao = new OrderDao(new JdbcTemplate(new MysqlDataSource()));
List<?> objects = orderDao.selectAll();
}
}
模板模式在我们工作中用到得非常多,也非常实用。它将我们重复的逻辑代码统一抽取到了一个公共的父类中,将可变行为留给子类去实现,使用者能按照设计者的构想初衷去实现代码逻辑。总而言之,模板模式是一个非常使用的设计模式。