加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Groovy探索之闭包 二

发布时间:2020-12-14 17:00:36 所属栏目:大数据 来源:网络整理
导读:????????????????????????????????? Groovy探索之闭包 二 ? 自从编程进入面向对象时代,大家都在孜孜不倦的同面向过程作斗争。想想看,我们大家都爱使用、并且奉为经典的Bang of Four的模式,有多少是针对if…else…这样的语句进行优化的。但是,即使我们做
????????????????????????????????? Groovy探索之闭包 二
?
自从编程进入面向对象时代,大家都在孜孜不倦的同面向过程作斗争。想想看,我们大家都爱使用、并且奉为经典的Bang of Four的模式,有多少是针对if…else…这样的语句进行优化的。但是,即使我们做了如上述的大量努力,一些面向过程的语言仍然站在那里嘲笑着我们的无能。
一.解决经典的try…catch问题
不错,try…catch就是我们经常碰到的经典问题。看一看下面的一段代码:
??? public static List getDataFromExcel(String fileName, int beginRow, int endRow,ModelIntf model,String[] inputCols,List messages)
{
?????? List retn = new ArrayList();
?????? InputStream fs = null ;
?????? Workbook wb = null ;
?????? try
?????? {
?????????? fs = new FileInputStream(fileName);
?????????? wb = Workbook.getWorkbook(fs);
?????????? Sheet sh = wb.getSheet(0);
??????????
?????????? if ( logger .isDebugEnabled()) {
????????????? logger .debug( "SheetName = " + sh.getName());
?????????? }
??????????
?????????? int len = inputCols. length ;
??????????
?????????? String[] values = new String[len];
??????????
?????????? ……
?????? }
?????? catch (Exception e)
?????? {
?????????? if ( logger .isDebugEnabled()) {
??? ?????????? logger .debug( "ExcelReader" ,e);
?????????? }
?????????? e.printStackTrace();
?????? }
?????? finally
?????? {
?????????? try {
????????????? if (fs!= null )
????????????? {
????????????????? fs.close();
????????????? }
????????????? if (wb!= null )
????????????? {
????????????????? wb.close();
????????????? }
?????????? } catch (IOException e) {
????????????? // TODO Auto-generated catch block
????????????? e.printStackTrace();
?????????? }
?????? }
??? return retn;
}
?
上面的代码是我从使用JXL API读取Excel文档的一段代码,为了关注我们正在谈论的问题,我将其中一段代码删掉。这样,我们可以清楚的看到代码中的try…catch语句,以及它们所起的作用。
在我的这段读取Excel文档的代码中,有五六个类似这样的方法。它们都要使用这样的try…catch语句,而且它们除了在try语句段里面做的事情不同以外,在catch语句段和finally语句段里做的事情都是一样的。
难道我们都要把相同的catch语句段和finally语句段拷贝到各个方法里去吗?如果需要维护catch语句段和finally语句段的时候,是不是每个方法里都去修改?
看到这里,你一定想起更为经典的JDBC API的使用,并且拿出经典的Spring对JDBC的解决方案:JdbcTemplate。
不错,JdbcTemplate解决方案使用了Java内部类,的确是个不错的解决方案,我们使用起来感觉也相当的不错。但是,我前面在《Groovy探索之闭包 一》中说,Java内部类使用起来相当晦涩和繁琐,实际上并不好用。看到这里,Java的扇子们不要忙着给我扔臭鸡蛋,看看闭包的解决方案先。
下面的代码是我在Grails平台使用Gsql操作存储过程的一段代码,具体用来控制存储过程的事务:
? def doCallWithTransaction(Closure closure) throws DataInTransactionException
?{
??? ? def conn = dataSource.getConnection()
??? ?conn.setAutoCommit( false )
??? ? try
??? ?{
?????? ?StoredProcedureDao dao = new StoredProcedureDao(conn)
?????? ?
?????? ?closure. call (dao)
?????? ?
?????? ?conn.commit()
??? ?}
??? ? catch (Exception e)
??? ?{
?????? ?conn.rollback()
?????? ? throw new DataInTransactionException(e)
??? ?}
??? ? finally
??? ?{
?????? ?conn.close()
??? ?}
?}
?
可以看到,这段代码除了给出了相同的catch代码段和finally代码段,而将不同的代码执行都交给了一个闭包对象 closure
closure. call (dao)
那么,我们怎么使用这个方法呢?
? //inputList is two or more inputs
? def callWithTransaction(String procName,List inputList) throws DataInTransactionException
?{
??? ? this .doCallWithTransaction{
?????? ?dao ->
?????? ??inputList. each {
?????? ?????? dao. call (procName,it)
?????? ??}
??? ?}
?}
?
看看上面的代码,当使用一个 domain 对象的集成对存储过程进行调用的时候,我们需要考虑该操作的事务。通过调用 doCallWithTransaction ,我们轻松就控制了存储过程的事务。这样的编码的确既简单又直观。
下面我们来看看怎么解决上面的操作 Excel 文档的问题。
//closure 对象包装的是一段代码段,它具体对 Excel 文档进行操作
def getDataFromExcel(Closure closure)
{
?????? List retn = new ArrayList();
?????? InputStream fs = null ;
?????? Workbook wb = null ;
?????? try
?????? {
?????????? fs = new FileInputStream(fileName);
?????????? wb = Workbook.getWorkbook(fs);
?????????? Sheet sh = wb.getSheet(0);
??????????
?????????? if ( logger .isDebugEnabled()) {
????????????? logger .debug( "SheetName = " + sh.getName());
??? ?????? }
??????????
???????
??????? // 上面的代码在每一个操作 Excel 的方法中都是相同的,可以照写
?
??????? // 下面是每一个操作 Excel 的方法中不同的代码,就把它封装在闭包里
??????? retn = closure. call (sh)
??????? // 注意:由于闭包封装的代码段需要操作 Sheet 对象,所以必须把 sh 对象传递给闭包对象。
?????? }
?????? catch (Exception e)
?????? {
?????????? if ( logger .isDebugEnabled()) {
????????????? logger .debug( "ExcelReader" ,e);
?????????? }
?????? ??? e.printStackTrace();
?????? }
?????? finally
?????? {
?????????? try {
????????????? if (fs!= null )
????????????? {
????????????????? fs.close();
????????????? }
????????????? if (wb!= null )
????????????? {
????????????????? wb.close();
????????????? }
?????????? } catch (IOException e) {
????????????? // TODO Auto-generated catch block
????????????? e.printStackTrace();
?????????? }
?????? }
??? return retn;
}
?
就这样,我们就轻松的完成了对操作 Excel 文档的 try…catch 代码的封装。下面使用这个方法:
// 这是我们最初看到的原始方法,我们使用了闭包对 try…catch 代码段进行封装以后,就可以在这个方法中使用它。
public static List getDataFromExcel(String fileName,List messages)
{
??? getDataFromExcel
{
??? sh ->
??? ?????? int len = inputCols. length ;
??????????
?????????? String[] values = new String[len];
?????????? // 开始使用 sh Excel 文档进行操作
?????????? ……
??? // 在最后记得返回一个 List 对象
}
}
这样,我们就可以在该类的四五个与“ getDataFromExcel(String fileName,List messages) ”功能相同的方法中使用上面的闭包了。
?
二.灵活的闭包
闭包不但在解决诸如try…catch这样的面向过程的语句中显得更为简单和易懂;同样,它还有比内部类更为灵活的一面。因为闭包可以定义在代码的很多地方,甚至是一个方法体内,这样使得它方法本身的变量,从而不必需要向闭包对象传递很多的变量。下面试举一例来看看这个问题。
我们在写标签的时候,标签经常有一些必填和非必填的属性。对于非必填的那些属性,如“id”和“alt”等等,我们需要判断它们是否有值。
??? def id = attrs[ "id" ]
??? if (id!= null &&!(id.trim()== '' ))
??? {
?????? sb. append ( " id=/"" )
?????? sb. append (id)
?????? sb. append ( "/"" )
}
?
??? def size = attrs[ "size" ]
??? if (id!= null &&!(id.trim()== '' ))
??? {
?????? sb. append ( " size=/"" )
?????? sb. append (size)
?????? sb. append ( "/"" )
}
遇到了这样的代码,大家都知道使用闭包了。如下:
??? def setProperty = {
?????? propertyName ->
?????????? def propertyValue = attrs[ "${propertyName}" ]
??????????????????????????? ? if (propertyValue!= null &&!(propertyValue.trim()== '' ))
?????????? {
????????????? sb. append ( " ${propertyName}=/"" )
????????????? sb. append (propertyValue)
????????????? sb. append ( "/"" )
?????????? }
}
?
可以看到,该闭包只能一个输入参数,但实际上还有“attrs”和“sb”两个参数没有通过闭包的输入参数获得。这是因为我们的 setProperty闭包直接定义在该标签实现体内,使得闭包可以直接使用这两个变量。下面是对该闭包的调用:
??? def propertyNames = [ 'disabled' , 'size' , 'maxlength' , 'readonly' ,
'tabindex' , 'alt' , 'id' , 'width' , 'height' ,
'onChange' , 'onClick' ]
??? propertyNames. each {
?????????? setProperty. call (it)
}
?
怎么样,闭包的使用是不是灵活得多?
?

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读