qiao88 2009-03-26 23:19
浏览 266
已采纳

模板方法和回调方法的困惑

我对他们的理解:
先看一个例子:

引用
jdbcTemplate.update()的源码

1. public int update(final String sql) throws DataAccessException {  
2.     Assert.notNull(sql, "SQL must not be null");  
3.     if (logger.isDebugEnabled()) {  
4.         logger.debug("Executing SQL update [" + sql + "]");  
5.     }  
6.  
7.     class UpdateStatementCallback implements StatementCallback, SqlProvider {  
8.         public Object doInStatement(Statement stmt) throws SQLException {  
9.             int rows = stmt.executeUpdate(sql);  
10.             if (logger.isDebugEnabled()) {  
11.                 logger.debug("SQL update affected " + rows + " rows");  
12.             }  
13.             return new Integer(rows);  
14.         }  
15.         public String getSql() {  
16.             return sql;  
17.         }  
18.     }  
19.     return ((Integer) <SPAN style="COLOR: #888888">execute</SPAN>(new UpdateStatementCallback())).intValue();  
20. }

1. public Object execute(StatementCallback action) throws DataAccessException {  
2.     Assert.notNull(action, "Callback object must not be null");  
3.  
4.     Connection con = DataSourceUtils.getConnection(getDataSource());  
5.     Statement stmt = null;  
6.     try {  
7.         Connection conToUse = con;  
8.         if (this.nativeJdbcExtractor != null &&  
9.                 this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {  
10.             conToUse = this.nativeJdbcExtractor.getNativeConnection(con);  
11.         }  
12.         stmt = conToUse.createStatement();  
13.         applyStatementSettings(stmt);  
14.         Statement stmtToUse = stmt;  
15.         if (this.nativeJdbcExtractor != null) {  
16.             stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);  
17.         }  
18.         Object result = <SPAN style="COLOR: #000000">action.doInStatement(stmtToUse);</SPAN>  
19.         handleWarnings(stmt.getWarnings());  
20.         return result;  
21.     }  
22.     catch (SQLException ex) {  
23.         // Release Connection early, to avoid potential connection pool deadlock  
24.         // in the case when the exception translator hasn't been initialized yet.  
25.         JdbcUtils.closeStatement(stmt);  
26.         stmt = null;  
27.         DataSourceUtils.releaseConnection(con, getDataSource());  
28.         con = null;  
29.         throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);  
30.     }  
31.     finally {  
32.         JdbcUtils.closeStatement(stmt);  
33.         DataSourceUtils.releaseConnection(con, getDataSource());  
34.     }  
35. } 


eg:A回调方法。B模板方法

怎样才能把B中的动态代码写成固定的啊?????
我们可以采用多态的方法,上面的代码就是采用多态的方法,

回调的方法是多态的(这样我们就可以写不同的代码了)


刚开时时,我认为模块和回调是为了代码的复用.我们可以把重复的代码写在模板中,把变化的写在回调方法中,
现在感觉模块和回调确实可以复用代码,但这不是他存在的主要原因。

谁能说说他主要的用途
貌似一切皆在他的名字中 模板(可以理解为相同的流程)
我们可以吧流程中不同的内容提取出来,
                       回调:貌似可以‘动态’的加入代码

希望高手来交流




问题补充
unsid 写道
另外,区别是回调还是模板方法,还有一个很重要的依据,你所变化的类是不是具有"一次性特征",思考一下comparable接口,为什么不设计在list之上?因为list里的元素排序方式单一性一次性,比如这次按价格排序只代表这次,下次按出厂日期排序.而你的例子里,适合用模板方法,因为你的实现类相对稳定,总共不会有太多种类的操作.其实回调就是"访问者"模式最简单的实现.

不明白,模板和回调是一起使用的吧???

我在模板方法中去回调。

你说的貌似他们是分开的,可以单独存在,
问题补充
凤舞凰扬 写道
     模板方法时一种模式,属于静态表现对象的结构关系。其中的抽象模板方法是构成一个整体行为中的一部分,这部分的行为抽象已经确定,而只是将具体的实现延迟到子类完成。
     回调不算是模式,它更多地是处理对象间的相互调用关系。回调一般是行为已经确定,而不确定调用者时常用。回调也就是把具体的行为传递给调用者。因为模板和回调都是将实际的对象调用关系延迟,所以会让人有一种错觉。其实很多时候,回调是用在事件处理、消息通知等,比如我们都知道的钩子程序。从这个角度说,回调是与观察器模式相似的,或者应该说回调是观察器模式的主要构成。
      在spring 的jdbctempate中确实用了回调,但是,它其实是一种变异的模板方法模式,只是因为用了无名内部类,所以让人忽略了对于callback中模板方法的实现而已。而所谓的回调其实只是通过一个统一的方法将模板实现类注入而已,将callback中模板方法所在的整体行为从callback中抽取到独立的template中了。
      不知道是否说得够清楚了,不过spring这个设计是一个蛮经典的设计。唯一的缺点就是随着方法调用的增多会导致JVM的OldGen中,匿名class对象会增多,每次full GC都会导致class unloading的情况。

感觉你说的和我理解的相差好大,我在好好看看,设计模式
问题补充
凤舞凰扬 写道
     模板方法时一种模式,属于静态表现对象的结构关系。其中的抽象模板方法是构成一个整体行为中的一部分,这部分的行为抽象已经确定,而只是将具体的实现延迟到子类完成。
     回调不算是模式,它更多地是处理对象间的相互调用关系。回调一般是行为已经确定,而不确定调用者时常用。回调也就是把具体的行为传递给调用者。因为模板和回调都是将实际的对象调用关系延迟,所以会让人有一种错觉。其实很多时候,回调是用在事件处理、消息通知等,比如我们都知道的钩子程序。从这个角度说,回调是与观察器模式相似的,或者应该说回调是观察器模式的主要构成。
      在spring 的jdbctempate中确实用了回调,但是,它其实是一种变异的模板方法模式,只是因为用了无名内部类,所以让人忽略了对于callback中模板方法的实现而已。而所谓的回调其实只是通过一个统一的方法将模板实现类注入而已,将callback中模板方法所在的整体行为从callback中抽取到独立的template中了。
      不知道是否说得够清楚了,不过spring这个设计是一个蛮经典的设计。唯一的缺点就是随着方法调用的增多会导致JVM的OldGen中,匿名class对象会增多,每次full GC都会导致class unloading的情况。

unsid 写道
实现功能差不多,回调简洁一些,因为模板方法要为每个类型生成一个最终实现类,回调类可以用无名内隐类来代替.另外使用回调的话可以放心地把主类声明为final而避免因子类复写了不该复写的方法而导致的错误.用回调还是模版方法,我觉得看情况吧,如果动态的方法中要用到好多类的变量,那么回调函数要有一个很长的参数表,非常不好理解,如果回调函数要实现多于一个的方法,那么无法用内隐类,也没有简洁性了,总之在设计过程中,能不用继承就不用.


你们两个是正确的。
  • 写回答

3条回答 默认 最新

  • phenixhwang 2009-03-26 23:19
    关注
     模板方法时一种模式,属于静态表现对象的结构关系。其中的抽象模板方法是构成一个整体行为中的一部分,这部分的行为抽象已经确定,而只是将具体的实现延迟到子类完成。
     回调不算是模式,它更多地是处理对象间的相互调用关系。回调一般是行为已经确定,而不确定调用者时常用。回调也就是把具体的行为传递给调用者。因为模板和回调都是将实际的对象调用关系延迟,所以会让人有一种错觉。其实很多时候,回调是用在事件处理、消息通知等,比如我们都知道的钩子程序。从这个角度说,回调是与观察器模式相似的,或者应该说回调是观察器模式的主要构成。
      在spring 的jdbctempate中确实用了回调,但是,它其实是一种变异的模板方法模式,只是因为用了无名内部类,所以让人忽略了对于callback中模板方法的实现而已。而所谓的回调其实只是通过一个统一的方法将模板实现类注入而已,将callback中模板方法所在的整体行为从callback中抽取到独立的template中了。
      不知道是否说得够清楚了,不过spring这个设计是一个蛮经典的设计。唯一的缺点就是随着方法调用的增多会导致JVM的OldGen中,匿名class对象会增多,每次full GC都会导致class unloading的情况。
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试