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) {
e.printstacktrace();
}
}
return
retn;
}
在我的这段读取Excel文档的代码中,有五六个类似这样的方法。它们都要使用这样的try…catch语句,而且它们除了在try语句段里面做的事情不同以外,在catch语句段和finally语句段里做的事情都是一样的。
看到这里,你一定想起更为经典的JDBC API的使用,并且拿出经典的Spring对JDBC的解决方案:JdbcTemplate。
不错,JdbcTemplate解决方案使用了Java内部类,的确是个不错的解决方案,我们使用起来感觉也相当的不错。但是,我前面在《Groovy探索之闭包 一》中说,Java内部类使用起来相当晦涩和繁琐,实际上并不好用。看到这里,Java的扇子们不要忙着给我扔臭鸡蛋,看看闭包的解决方案先。
{
def
conn = dataSource.getConnection()
@H_39_404@try
{
closure.
call
(dao)
conn.commit()
}
{
conn.rollback()
}
@H_39_404@finally
{
conn.close()
}
}
closure.
call
(dao)
那么,我们怎么使用这个方法呢?
//inputList is two or more inputs
{
dao ->
inputList.
each
{
dao.
call
(procName,it)
}
}
}
看看上面的代码,当使用一个
domain
对象的集成对存储过程进行调用的时候,我们需要考虑该操作的事务。通过调用
doCallWithTransaction
,我们轻松就控制了存储过程的事务。这样的编码的确既简单又直观。
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());
}
retn = closure.
call
(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) {
e.printstacktrace();
}
}
return
retn;
}
public
static
List getDataFromExcel(String fileName,List messages)
{
getDataFromExcel
{
sh ->
int
len = inputCols.
length
;
String[] values =
new
String[len];
//
开始使用
sh
对
Excel
文档进行操作
……
}
}
二.灵活的闭包
闭包不但在解决诸如try…catch这样的面向过程的语句中显得更为简单和易懂;同样,它还有比内部类更为灵活的一面。因为闭包可以定义在代码的很多地方,甚至是一个方法体内,这样使得它方法本身的变量,从而不必需要向闭包对象传递很多的变量。下面试举一例来看看这个问题。
def
id = attrs[
"id"
]
{
sb.
append
(
" id=/""
)
sb.
append
(id)
sb.
append
(
"/""
)
}
def
size = attrs[
"size"
]
{
sb.
append
(
" size=/""
)
sb.
append
(size)
sb.
append
(
"/""
)
}
遇到了这样的代码,大家都知道使用闭包了。如下:
def
setProperty = {
propertyName ->
def
propertyValue = attrs[
"${propertyName}"
]
{
sb.
append
(
" ${propertyName}=/""
)
sb.
append
(propertyValue)
sb.
append
(
"/""
)
}
}
可以看到,该闭包只能一个输入参数,但实际上还有“attrs”和“sb”两个参数没有通过闭包的输入参数获得。这是因为我们的
setProperty闭包直接定义在该标签实现体内,使得闭包可以直接使用这两个变量。下面是对该闭包的调用:
'tabindex'
,
'alt'
,
'id'
,
'width'
,
'height'
,
'onChange'
,
'onClick'
]
propertyNames.
each
{
setProperty.
call
(it)
}
怎么样,闭包的使用是不是灵活得多?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。