Spring对JDBC的抽象和对Hibernate的集成,都采用了一种理念或者处理方式,那就是Template模式与相应的Callback
接口相结合。比如JdbcTemplate的execute方法、HibernateTemplate的execute方法。
采用模板方法模式是为了以一种统一而集中的方式来处理资源的获取和释放
以JdbcTempalte为例,如下:
public abstract class JdbcTemplate {
public final Object execute(String sql){
Connectioncon=null;
Statementstmt=null;
try
{
con=getConnection();
stmt=con.createStatement();
ObjectretValue=executeWithStatement(stmt,sql);
returnretValue;
}
catch(SQLExceptione){
...
}
finally
{
closeStatement(stmt);
releaseConnection(con);
}
}
protected abstract ObjectexecuteWithStatement(Statement stmt,String sql);
}
这样处理之后,JDBC代码的使用得到了规范,连接释放等问题也得到了统一的管理。
Templatemethod被广泛的使用,像Servlet就是使用这个模式。Template mothod模式虽然能简化很多重复的代码,但这种模式的也有不少限制。
Templatemothod将一个功能的实现分成许多小的步骤,在父类中定义了这些步骤的顺序,让子类来具体实现每一个小的步骤。这些小
的步骤是protected,以防止用户不正确的使用这些小的步骤而产生异常。这样就产生了一个限制,那就是你需要继承Template,然后
在子类中重新实现具体的小步骤。
如果这个Template有许多方法,就像JdbcTemplate,如果你每次继承这个庞大的类,然后只是重写某个小步骤中来订制你自己的功能,
就会显得非常笨重,更何况数据库操作使用的如此频繁,难道你每进行一个操作就通过继承订制一个,显然不可能这么做。
看看引入Callback之后的代码
public interface StatementCallback{
Object doWithStatement(Statementstmt);
}
public class JdbcTemplate {
public final Object execute(StatementCallbackcallback){
Connectioncon=null;
Statementstmt=null;
try
{
con=getConnection();
stmt=con.createStatement();
ObjectretValue=callback.doWithStatement(stmt);
returnretValue;
}
catch(SQLExceptione){
...
}
finally
{
closeStatement(stmt);
releaseConnection(con);
}
}
...//其它方法定义
}
使用如下:
JdbcTemplatejdbcTemplate=...;
final String sql=...;
StatementCallback callback=new StatementCallback(){
publicObject=doWithStatement(Statement stmt){
return ...;
}
}
jdbcTemplate.execute(callback);
CallBack避免了用户继承Template,而是直接让用户实现去CallBack接口,达到了去掉重复代码的效果;只需要实现某些CallBack就可轻松订制出Template,增加了很大的灵活性。
那么什么时候才是Callback模式与Template模式结合的最佳时机呢?
从UML关系分析
Template模式使用继承,结合Callback之后,只是简单的依赖,耦合性变弱,不用必须从父类继承多余的东西。
从对象的粒度分析
一般情况下如果一个操作的子步骤比较少(三个以下),比如用户只需要定制一个方法能就达到用户的要求,或者你不想生
成太细粒度的对象时,用Callback来代替templatemethod能够获得更好的灵活性。
而如果子步骤多,需要我们真正去具体实现,则使用templatemethod。因为你可能需要传递多个Callback作为参数,并让
用户去实现,这相当于你把每个小步骤封装成为接口,然后分别实现,这时便会产生大量的类和接口,显然没有达到方便灵
活的效果。