逝去的青春

勇往直前

2006年3月29日 #

回调函数在Spring中的使用

   这是一种对单个方法的参数使用控制反转,把控制权和差错处理交给框架来处理。严格的说,这是一种Strategy模式的特例,他们的区别就在于接口的复杂度不同。
   在Spring的JdbcTemplate中就使用了这种模式。JdbcTemplate实现了query()方法,参数是SQL字符串,和一个实现了回调接口的,将在读取resultSet每行时被调用。

1 public   interface  RowCallbackHandler 
2 {
3      void  processRow(ResultSet rs)  throws  SQLException;
4 }
 


  query()方法封装了对JDBC底层API的调用。

public   void  query(String sql, RowCallbackHandler callbackHandler)  throws  JdbcSqlException 
{
    Connection con 
=   null ;
    PreparedStatement ps 
=   null ;
    ResultSet rs 
=   null ;
    
try  
    
{
        con 
=   < code to get connection >
        ps 
=  con.prepareStatement (sql);
        rs 
=  ps.executeQuery();
        
while  (rs.next()) 
        
{
            callbackHandler.processRow(rs);
        }

        rs.close();
        ps.close();
    }
 
    
catch  (SQLException ex) 
    
{
        
throw   new  JdbcSqlException( " Couldn't run query [ "   +  sql  +   " ] " , ex);
    }

    
finally  
    
{
        DataSourceUtils.closeConnectionIfNecessary(
this .dataSource, con);
    }

}


   在上面的例子中,JdbcSqlException继承了java.lang.RuntimeException,也就是说调用者可以选择去捕获它,但是这不是必须的。假如实现了回调接口的子类里的方法出错,而且不是RuntimeException的子类,也就是必须捕获的异常,但是query()方法中在逻辑上是没有办法捕获它的。所以Rod_Johnson把接口定义成JdbcTemplate的inner interface。这就可以JdbcTemplate就可以捕获它。
   回调方法也是框架的一种基本方法,比如java.io.File类中的listFiles(FilenameFilter filter),FilenameFilter就是一个接口,我们实现这个接口中的方法accept(File dir, String name) ,这就是一个典型的回调方法。
   观察者模式的使用符合开闭原则,并且分离了关注点。这种对模块修改开发,影响关闭的原则促进了AOP面向方面编程的发展。Spring中的AOP可能就是这种思想的实现,个人猜测而已。    
    把方法的参数放在一个类中,这样以后要增加参数的话,不用修改方法签名,感觉很干净,唯一可能的缺点是可能对性能有所下降,不过很小。如果没有用EJB的话,应该差不多。

   对异常的处理,分为checked和unchecked异常,checked异常是继承java.lang.Exception的。Unchecked异常继承java.lang.RuntimeException。Rod_Johnson主张在对出现异常后,程序不能处理,只能给予没用的提示时用RuntimeException,因为RuntimeException容器会自动处理。关于异常的详细说明,我也没看明白,希望那位大虾能指点指点。

备注:本文主要内容来源于Rod_Johnson的大作,强烈建议看原版!

posted @ 2006-03-30 21:57 逝去的年华 阅读(1448) | 评论 (0)编辑 收藏

Template模式和Strategey模式

         在学习Spring的过程中经常看到一些大虾推荐阅读Rod_Johnson的<Expert_One-on-One_J2EE_Design_and_Development>书,据说此书的第四章每个学java人都要看看.好不容易搞到pdf版,可惜是E文的,中文的搞不到,没办法只好硬着头皮看下去。
   第四章主要讲的是面向对象的设计模式,怎么采用一致的编码公约,怎么利用也有的系统.这对于理解Spring框架有很大的帮助!因为这是Spring之父的编程思想。):
   关于接口的好处及组合模式的有点,我这里就不说了。
   Template模式:适用范围,我们知道某个业务或算法的步骤,但是不知道怎么把每步的顺序。Template模式采用在abstract类中有个Public and final的方法封装了调用每步的顺序,也就是说控制了工作流程。所有的继承类也就只要实现每步的具体方法。这是控制反转的一种表现,以前都是我们在程序中去调用API中的方法,现在是我们实现API某个类中的抽象方法给该类调用!这种控制反转的机制,是框架的代码基础.比如,EJB中的Init()和destory()方法等等.Spring框架中的对数据持久层的实现就是很好的例子!
下面把书中的例子COPY下:
  AbstractOrderEJB父类实现了商业逻辑,包括用户是否金额超现和对大的订单进行打折,palceOrder()方法就是那个工作流方法。

abstract   class  AbstractOrderEJB
{
    
public   final  Invoice placeOrder ( int  customerId, InvoiceItem[] items)
        
throws  NoSuchCustomerException, SpendingLimitViolation 
    
{
        
int  total  =   0 ;
        
for  ( int  i  =   0 ; i  <  items. length; i ++
        
{
            total 
+=  getItemPrice (items [i])  *  items [i] .getQuantity();
        }

        
if  (total  >  getSpendingLimit (customerId) )
        
{
            getSessionContext() .setRollbackOnly();
            
throw   new  SpendingLimitViolation (total, limit);
        }

        
else   if  (total  >  DISCOUNT_THRESHOLD) 
        
{
            
//  Apply discount to total
        }

        
int  invoiceId  =  placeOrder (customerId, total, items);
        
return   new  InvoiceImpl (iid, total);
    }


    
protected   abstract   int  getItemPrice(InvoiceItem item);

    
protected   abstract   int  getSpendingLimit(customerId) throws  NoSuchCustomerException;

    
protected   abstract   int  placeOrder( int  customerId,  int  total,InvoiceItem[] items);
  }

   getItemPrice,getSpendingLimit,placeOrder这三个方法,是protected and abstract的,由子类来实现。
   Strategey模式和Template模式比较相似.用Strategey模式对上个例子进行改造:把三个单独的方法放入一个接口中,工作流方法进行如下修改:

 1 public   class  OrderEJB
 2 {
 3      private  DataHelper dataHelper;
 4      public   void  setDataHelper (DataHelper newDataHelper) 
 5      {
 6          this .dataHelper  =  newDataHelper;
 7     }

 8      public   final  Invoice placeOrder ( int  customerId, InvoiceItem[] items)
 9          throws  NoSuchCustomerException, SpendingLimitViolation 
10      {
11          int  total  =   0 ;
12          for  ( int  i  =   0 ; i  <  items.length; i ++
13          {
14             total  +=   this .dataHelper.getItemPrice(items[i])  *
15             items[i].getQuantity();
16         }

17          if  (total  >   this .dataHelper.getSpendingLimit(customerId)) 
18          {
19             getSessionContext() .setRollbackOnly();
20              throw   new  SpendingLimitViolation(total, limit);
21         }
 
22          else   if  (total  >  DISCOUNT_THRESHOLD) 
23          {
24              //  Apply discount to total
25         }

26          int  invoiceId  =   this .dataHelper.placeOrder (customerId, total, items);
27          return   new  InvoiceImpl (iid, total);
28     }

29 }

   Stratery模式比Temlater模式复杂点,但是它具有更高的灵活性,对于实际项目一些流程的控制有很好的作用!这是本人的观点,不一定正确,仅供参考。
   
在下面的情况下,用Stratery模式比Temlater模式更好:
1,每步都是可变的
2,实现每步的类需要一个独立的继承体系
3,实现每步的类要和其他的类打交道
4,实现每步的类要实现多态性

备注:本文主要内容来源于Rod_Johnson的大作,强烈建议看原版!

posted @ 2006-03-29 20:49 逝去的年华 阅读(1464) | 评论 (0)编辑 收藏