【发布时间】:2014-02-21 03:34:09
【问题描述】:
Groovy 中的 null 安全运算符非常适合减少代码并使内容更具可读性。我们可以从这里开始:
def customer = getCustomer(custNo)
if(!customer)
throw new Exception("Invalid customer: ${custNo}")
def policy = customer.getPolicy(policyNo)
if(!policy)
throw new Exception("Invalid policy: ${policyNo}")
def claim = policy.getClaim(claimNo)
if(!claim)
throw new Exception("Invalid claim: ${claimNo}")
..到这个...
def claim = getCustomer(custNo)?.getPolicy(policyNo)?.getClaim(claimNo)
但没有什么是免费的;使用空/安全导航,如果 claim 为空,则不是很明显是什么导致它:custNo、policyNo 或 claimNo 可能无效。
我们可以返回并开始检查什么是 null,但这会适得其反,实际上,这甚至是不可能的,因为中间对象不存储在变量中。
所以问题是:是否可以在使用 null/安全导航链接方法调用时识别什么是 null?
更新
我使用dynamic method invocation 对此进行了另一次尝试。它需要一个 init 目标(通常是一个 dao)来初始化对象(在这种情况下是客户),以及一个包含方法名称作为字符串(以参数作为值)的映射。使用迭代器,invokeChain 简单地遍历映射(链);如果链中的任何内容返回 null,则识别导致它的方法变得微不足道。
def invokeChain = { initTarget, chain ->
def obj
chain.eachWithIndex{ it, idx ->
//init obj from dao on first iteration only,
//remaining iterations get from obj itself
obj = (!idx) ? initTarget."$it.key"(it.value) : obj?."$it.key"(it.value)
if(!obj)
throw new Exception("${it.key}(${it.value}) returned null")
}
obj
}
用法
为initTarget 模拟customer dao...我已插入null 作为getClaim() 的返回类型,这应该会引发异常。
def static getCustomer = { custNo ->
[ getPolicy: { p ->
[getClaim:{ c ->
null //"Claim #${c}"
}]
}]
}
..使用invokeChain,很简单:
def claim = invokeChain(this, [getCustomer:123, getPolicy:456, getClaim:789])
...按预期抛出异常:
Exception in thread "main" java.lang.Exception: getClaim(789) returned null
我喜欢这种方法,因为它紧凑、可读且易于使用;你怎么看?
【问题讨论】:
-
我提供了一个有效的拦截示例,并稍微扩展了一个答案。感谢您对调查的有趣刺激。
-
是的,这个解决方案非常好。它不是在拦截?语法,并且需要对现有代码进行一些更改。我可以注意到,映射顺序可能会改变方法调用,但由于 Groovy 默认使用 LinkedHashMap - 这似乎很好。我也尝试玩MOP,只是为了好玩,如果我取得了好成绩,会在这里发布。抱歉迟到了评论,我有点忙。
标签: groovy