設計模式之模板模式(java實現)
模板模式(Template):行為型模式的一種,定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。Template Method 使得子類可以不改變 一個演算法的結構即可重定義該演算法的某些特定步驟。
簡單的理解就是,一個架構或者業務的主體邏輯和流程是確定的,那麼我們可以將它的這些邏輯流程抽象出來,然後真正具體實現的時候在它的子類之中進行實現。
這是第一種思想,實現相對來說並不困難,引申的另一種思想就是,如果當一個業務是固定而且繁瑣的,但呼叫又是比較頻繁的話,每次呼叫用到的引數或許不同,那麼也可以考慮使用的模板模式。
在Spring中就有一個比較重要而且常用的類JdbcTemplate,作為資料庫的連線,會經常被使用到,但它裡面的方法繁多,並不想被繼承,所以我們可以把變化的東西抽出 來作為一個引數傳入 JdbcTemplate 的方法中。但是變化的東西是一段程式碼,而且這段程式碼會用到JdbcTemplate 中的變數。怎麼辦?那我們就用回撥物件吧。在這個回撥物件中定義一個操縱JdbcTemplate 中變數的方法,我們去實現這個方法,就把變化的東西集中到這裡了。然後我們再傳入 這個回撥物件到 JdbcTemplate,從而完成了呼叫。這就是 Template Method 不需要繼承的另一種實 現方式。
現在舉一個例子吧,在資料庫連線中,執行的流程是固定的:
1.獲取連線,2.建立語句集,3.執行語句集,並獲取結果集,4.解析語句集,5.關閉結果集,6.關閉語句集,7關閉連線
所以我們可以把這部分單獨拿出來放在JdbcTemplete裡面,而實際的查詢語句,是經常變化的。
部分JdbcTemplate程式碼:
package Template; import java.util.List; import javax.sql.DataSource; import javax.swing.tree.RowMapper; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; public class JdbcTemplate { private DataSource dataSource; public JdbcTemplate(DataSource dataSource){ this.dataSource = dataSource; } private Connection getConnection() throws Exception{ return this.dataSource.getConnection(); } private PreparedStatement createPreparedStatement(Connection conn,String sql) throws Exception{ return conn.prepareStatement(sql); } private ResultSet executeQuery(PreparedStatement pstmt,Object [] values) throws Exception{ for (int i = 0; i <values.length; i ++){ pstmt.setObject(i,values[i]); } return pstmt.executeQuery(); } private void closeStatement(Statement stmt) throws Exception{ stmt.close(); } private void closeResultSet(ResultSet rs) throws Exception{ rs.close(); } private void closeConnection(Connection conn) throws Exception{ //通常把它放到連線池回收 } private List<?> parseResultSet(ResultSet rs, RowMapper rowMapper) throws Exception{ List<Object> result = new ArrayList<Object>(); int rowNum = 1; while (rs.next()){ result.add(rowMapper.mapRow(rs,rowNum ++)); } return result; } public List<?> executeQuery(String sql,RowMapper<?> rowMapper,Object [] values){ try { //1、獲取連線 Connection conn = this.getConnection(); //2、建立語句集 PreparedStatement pstmt = this.createPreparedStatement(conn,sql); //3、執行語句集,並且獲得結果集 ResultSet rs = this.executeQuery(pstmt,values); //4、解析語句集 List<?> result = this.parseResultSet(rs,rowMapper); //5、關閉結果集 this.closeResultSet(rs); //6、關閉語句集 this.closeStatement(pstmt); //7、關閉連線 this.closeConnection(conn); return result; }catch (Exception e){ e.printStackTrace(); return null; } } }
對應資料庫中成員Member類:
package com.gupaoedu.vip.pattern.template.entity; /** * Created by Tom on 2018/3/11. */ public class Member { private String username; private String password; private String nickName; private int age; private String addr; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getNickName() { return nickName; } public void setNickName(String nickName) { this.nickName = nickName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } }
對應DAO查詢類:
package Template.dao;
import Template.JdbcTemplate;
import Template.entity.Member;
import javax.swing.tree.RowMapper;
import java.sql.ResultSet;
import java.util.List;
public class MemberDao {
private JdbcTemplate jdbcTemplate = new JdbcTemplate(null);
public List<?> query(){
String sql = "select * from t_member";
return JdbcTemplate.executeQuery(sql,new RowMapper<Member>(){
@Override
public Member mapRow(ResultSet rs, int rowNum) throws Exception {
Member member = new Member();
member.setUsername(rs.getString("username"));
member.setPassword(rs.getString("password"));
member.setAge(rs.getInt("age"));
member.setAddr(rs.getString("addr"));
return member;
}
},null);
}
}
需要的Rowmapper
package Template;
import java.sql.ResultSet;
public interface Rowmapper<T> {
public T mapRow(ResultSet rs, int rowNum) throws Exception;
}
以上並不算特別完整,一個是具體需要建立相對應資料庫,加入依賴,所以這裡只是舉例。
可以看到,一個是但業務架構定下來之後,基礎流程可以使用模板方法,另一個但單獨的比較複雜但是流程固定的單個功能確定的是後也可以使用模板方法