首页 > 代码库 > 模板方法与回调函数

模板方法与回调函数

     还记得在刚开始学习JDBC时,每一次SQL执行都要经历从连接的获取、执行SQL、获取结果等,这些是一个流程性的动作。在大二时,刚刚学会没多久后,当时我正在学习JSP、Servlet(我的Java是自学的),有一个高中的同学让我帮她做课程设计。现在还依旧记得,那是一个校园一卡通项目,功能很少,整个课程设计涉及到了10多个SQL语句。

    我当时写代码时,把所有的SQL语句都写在了一个Java文件中。每一个SQL语句的执行都要经历:

// 获取连接Connection conn=getConnection();// 自定义的// 获取语句PreparedStatement psmt=conn.prepareStatement(sql);// 设置参数// ....// SQL 执行 psmt.executeUpdate或者psmt.executeQuery// 获取结果// 从ResultSet中取数// 关闭连接 close()

 

 当代码写了400多行时,我就感觉到这样写太麻烦了,有没有一个模板来处理这个过程呀,这样写下去太麻烦了,这是我当时的真实想法。

    我就在想能不能把这个烦人的过程放到一个模板里呢?不同的地方只有SQL执行和结果是如何处理,前面的过程都是一样的。那么我把SQL执行与结果处理拿出来,整个过程的其他部分不变,应该是可以的吧。可以使用抽象类来完成这个功能。

当时想到的是:

public abstract class JDBCTemplate {   private String url;   private String driver;   private String user;   private String password;   protected Connection conn;     public JDBCTemplate(){        }     public JDBCTemplate(String driver, String url, String user, String password){      this.driver=driver;      this.url=url;      this.user=user;      this.password=password;   }//// getter, setter就不粘出来了。 public Connection getConnection(){      try {         Class.forName(driver);         conn=DriverManager.getConnection(url, user, password);      } catch (Exception e) {        e.printStackTrace();      }      return conn;    }       public void close(PreparedStatement statement) throws Exception{        if (statement!=null){            statement.close();        }        if(conn!=null){            conn.close();        }    } protected final Object template(String sql, Object[] params){conn=getConnection();PreparedStatement psmt=null;        try{            psmt=conn.prepareStatement(sql);            for (int i=0; i<params.length; i++){                psmt.setObject(i+1, params[i]);            }return executeAndGetResult(psmt);        }catch (Exception e){            e.printStackTrace();            return e;        }        finally {            try{            close(psmt);            }catch (Exception e){                e.printStackTrace();            }        }} public abstract Object executeAndGetResult(PreparedStatement psmt);}
View Code

 

这样一来,executeAndGetRresult就由子类来完成,并且也不用再写那些烦人的过程了。当时的我,并不知道,这样写其实就是应用了模板方法模式。 

 

=============================================================

 

再后来,在学习AJax时,通过网上知道一种函数:callback,回调函数,也成为钩子函数。当时对此并不了解,上网查询学习,多多少少对回调函数有种模糊的概念。当时我想到了我之前写的那个JDBCTemplate,能否使用Callback来调整代码呢?

 

于是我改造了代码:

// 添加了一个回调接口public interface ResultSetHandler {   public Object handle(PreparedStatement statement);} //对模板方法接口做如下调整:protected final Object template(String sql, Object[] params, ResultSetHandler handler){        Connection conn=getConnection();        PreparedStatement psmt=null;        try{            psmt=conn.prepareStatement(sql);            for (int i=0; i<params.length; i++){                psmt.setObject(i+1, params[i]);            }            return handler.handle(psmt);        }catch (Exception e){            e.printStackTrace();            return e;        }        finally {            try{            close(psmt);            }catch (Exception e){                e.printStackTrace();            }        }    } 
View Code

也就是说,整个调整只换了template方法中的一句:由executeAndGetResult(psmt)调整为handler.handle(psmt); 

并把tempalte的abstract去掉了。调整后,感觉这种方式比第一种更好,只是当时的我依旧不知道什么是模板方法模式。我只知道,这样写挺好的,感觉心里很爽。于是我把这个类一直保留着,尽管后来没有使用它。

 

    后来在学习设计模式的模板方法模式时,我终于知道,原来我就用过模板方法模式,只是我不知道而已。

 

=================================================================

在GOF设计模式中是这么描述设计模式的:

    模板方法定义了一个算法步骤,并允许子类为一个或者多个步骤提供实现。

 

 

 

模板方法模式的类图如下:

 

 

上面的类图中,primitiveOperation1、 primitiveOperation2是抽象方法,就是整个算法中的不确定部分。他们要在模板方法中使用。我第一次写的那个JDBCTemplate中的executeAndGetResult就是这样的。

 

模板方法模式体系了对抽象编程的设计原则。

 

 

使用模板方法模式的实现中,主要是通过继承的方式,让父类在运行期间可以调用子类的方法。在Java开发中,在模板方法与回调函数结合使用时,就不需要通过继承来完成变化部分的代码了,通过Java的匿名内部类,同样可以完成上面的上述功能。

例如我的JDBCTemplate的第二版中使用了接口的方式。

接下来,我在JDBCTemplate内部添加一个方法:

 

public int save(String sql, Object[] params){       return (Integer)template(sql,params, new ResultSetHandler() {           public Object handle(PreparedStatement statement) {               int result=0;               try{                   result=  statement.executeUpdate();               }catch (Exception e){                   e.printStackTrace();               }               return result;           }       });    }
View Code

这是一个save数据的方法。使用过程中调用了template(String sql, Object[] params, ResultSetHandler handler);并不是使用子类来继承JDBCTemplate 

而是子啊方法调用时使用了匿名内部类。

 

这样做(使用Callback)可以说是TemplateMethod实现方式的一个变形。

 

 至于GOF设计模式书上说的那些关于模板方法模式的其他功能,一看便知,这里就不再说明了。