我们平时的入职流程是填写入职登记表→打印简历 →复印学历→复印身份证→签订合同→安排工位等,这个流程是针对每个人都是这样的,这样的可以称为模板
模板模式又成模板方法模式,是指定义一个算法骨架,并允许子类为一个或者多个步骤提供实现 。模板模式使得子类可以子类在不改变算法结构的情况下,重新定义算法的某些步骤,属于行为设计模式。模板模式使用与以下场景:
1.一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
2.各子类中的公共的行为被提取出来并集中到一个公共的父类中,从而避免了代码重复。
public abstract class AbstaractClass {
protected void step1(){
System.out.println("AbstaractClass+step1");
}
protected void step2(){
System.out.println("AbstaractClass+step2");
}
protected void step3(){
System.out.println("AbstaractClass+step3");
}
//加final防止子类覆写
public final void tempMeth(){
step1();
step2();
step3();
if (cheeck()){
step4();
}
}
protected boolean cheeck(){
return false;
}
protected void step4(){
System.out.println("判断是否走这一步");
};
}
public class StepA extends AbstaractClass {
private boolean ret;
public void setRet(boolean ret) {
this.ret = ret;
}
@Override
protected void step1(){
System.out.println("StepA+step1");
}
@Override
protected boolean cheeck(){
return this.ret;
}
public class StepB extends AbstaractClass {
@Override
protected void step2(){
System.out.println("StepB+step2");
}
}
public class SteptC extends AbstaractClass {
@Override
protected void step3(){
System.out.println("SteptC+step3");
}
}
public class StepTest {
public static void main(String[] args) {
StepA stepA = new StepA();
stepA.setRet(true);
stepA.tempMeth();
}
}
通过以上的案例,模板模式已经有了一个基本的印象。
利用模板模式重构JDBC
public abstract class JdbcTemplate { private DataSource dataSource; public JdbcTemplate(DataSource dataSource){ this.dataSource = dataSource; } public List<?> executQuery(String sql,RowMapper<?> rowMapper,Object[] values){ try { //获取连接 Connection conn = this.getConnection(); //创建语句集 PreparedStatement pstm = this.createPrepareStatement(conn,sql); //执行语句集 ResultSet rs =this.executQuery(pstm,values); //处理结果集 List<?> result = this.paresResultSet(rs,rowMapper); //关闭结果集 this.closeResultSet(rs); //关闭语句集 this.closeStatement(pstm); //关闭连接 this.closeConnection(conn); }catch (Exception e){ e.printStackTrace(); } return null; } protected void closeConnection(Connection conn)throws Exception{ conn.close(); }; protected void closeStatement(PreparedStatement pstm)throws Exception{ pstm.close(); }; protected void closeResultSet(ResultSet rs)throws Exception{ rs.close(); }; protected List<?> paresResultSet(ResultSet rs, RowMapper<?> rowMapper)throws Exception{ List<Object> result = new ArrayList<>(); int rowNum = 1; while (rs.next()){ result.add(rowMapper.mapRow(rs,rowNum++)); } return result; }; protected ResultSet executQuery(PreparedStatement pstm, Object[] values)throws Exception{ for (int i = 0;i<values.length;i++){ pstm.setObject(i,values[i]); } return pstm.executeQuery(); }; protected PreparedStatement createPrepareStatement(Connection conn, String sql)throws Exception{ return conn.prepareStatement(sql); }; public Connection getConnection() throws Exception { return this.dataSource.getConnection(); } }
public class Member { private String username; private String password; 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 class MemberDa extends JdbcTemplate { public MemberDa(DataSource dataSource) { super(dataSource); } public List<?> selectAll(){ String sql = "select * from t_member"; return super.executQuery(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")); return member; } },null); } }
public interface RowMapper<T> { T mapRow(ResultSet re,int rowNum)throws Exception; }
public class MemberTest { public static void main(String[] args) { MemberDa memberDa = new MemberDa(null); List<?> list = memberDa.selectAll(); System.out.println(list); } }
模板模式在HttpServlet中有应用,service(),doGet(),doPost()都是模板方法的 抽象实现
Mybatis框架中也有一些经典的应用,BaseExecutor类。
.... public abstract class BaseExecutor implements Executor { .... protected abstract int doUpdate(MappedStatement var1, Object var2) throws SQLException; protected abstract List<BatchResult> doFlushStatements(boolean var1) throws SQLException; protected abstract <E> List<E> doQuery(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, BoundSql var5) throws SQLException; protected abstract <E> Cursor<E> doQueryCursor(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4) throws SQLException; ....
看一下其之类SimpleExecutor中的doUpdate()
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { Statement stmt = null; int var6; try { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null); stmt = this.prepareStatement(handler, ms.getStatementLog()); var6 = handler.update(stmt); } finally { this.closeStatement(stmt); } return var6; }
对比BatchExecutor中的doUpate()
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, (ResultHandler)null, (BoundSql)null); BoundSql boundSql = handler.getBoundSql(); String sql = boundSql.getSql(); Statement stmt; if(sql.equals(this.currentSql) && ms.equals(this.currentStatement)) { int last = this.statementList.size() - 1; stmt = (Statement)this.statementList.get(last); this.applyTransactionTimeout(stmt); handler.parameterize(stmt); BatchResult batchResult = (BatchResult)this.batchResultList.get(last); batchResult.addParameterObject(parameterObject); } else { Connection connection = this.getConnection(ms.getStatementLog()); stmt = handler.prepare(connection, this.transaction.getTimeout()); handler.parameterize(stmt); this.currentSql = sql; this.currentStatement = ms; this.statementList.add(stmt); this.batchResultList.add(new BatchResult(ms, sql, parameterObject)); } handler.batch(stmt); return -2147482646; }
总结模板模式的优缺点
优点:
1.利用模板模式将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
2.将不同的代码放到不同子类中,通过子类的的拓展增加新的行为,可以提高代码的拓展性。
3.把不变的行为写到父类中,去除子类的重复代码,提供了一个很好的代码复用平台,符合开闭原则
缺点
1.每个抽象类都需要一个子类来实现,导致了类的增加
2.类数量的增加间接地增加了系统的复杂性
3.因为继承关系自身的缺点,如果父类添加新的抽象方法,所有的子类都要改写一遍