Groovy实现类Shell管道式调用及闭包值修改的优化方案咨询
问题
想要实现类似Shell管道的调用方式,满足以下需求:
- 调用
foo( 'abc' )直接返回默认结果'abc ~> 123' - 调用
foo( 'abc' ).bar( 'efg' )返回带额外参数的结果'efg : abc ~> 123'
先后进行了三次尝试,但都存在问题:
第一次尝试
def foo ( String aStr ) { String constant = '123' String result = "${aStr} ~> ${constant}" [ bar : { String bStr -> result = "${bStr} : ${result}"; return result } ] println result } foo( 'abc' ) // abc ~> 123 foo( 'abc' ).bar( 'efg' ) // java.lang.NullPointerException: Cannot invoke method bar() on null object
直接调用foo('abc')正常,但调用foo('abc').bar('efg')会抛出空指针异常——因为foo最后执行println后返回null,无法调用bar方法。
第二次尝试
def foo ( String aStr ) { String constant = '123' String result = "${aStr} ~> ${constant}" [ bar : { String bStr -> result = "${bStr} : ${result}"; println "${result}" } , default : { println result } ] } foo( 'abc' ).bar( 'efg' ) // efg : abc ~> 123 foo( 'abc' ).default() // abc ~> 123
实现了两种调用,但需要额外调用default()才能获取默认结果,且结果只能通过println输出,无法直接返回字符串用于后续操作。
第三次尝试
def foo ( String aStr ) { String constant = '123' String result = "${aStr} ~> ${constant}" [ bar : { String bStr = '' -> result = "${bStr ? "${bStr} : " : ''}${result}"; return result } ] } foo( 'abc' ) // [bar:ConsoleScript22$_foo_closure1@5e7667fd] foo( 'abc' ).bar() // abc ~> 123 foo( 'abc' ).bar( 'efg' ) // efg : abc ~> 123
bar支持无参调用获取默认结果,但直接调用foo(..)返回的是Map对象,而非预期的字符串结果。
优化实现方案
可以利用Groovy的Expando类实现,它允许动态添加方法,同时重写toString()方法,让直接调用foo()时返回预期字符串,调用bar()时返回处理后的结果:
def foo(String aStr) { String constant = '123' String baseResult = "${aStr} ~> ${constant}" def expando = new Expando() // 实现bar方法 expando.bar = { String bStr -> return "${bStr} : ${baseResult}" } // 重写toString,直接调用foo时返回默认结果 expando.toString = { return baseResult } return expando } // 测试调用 println foo('abc') // abc ~> 123 println foo('abc').bar('efg') // efg : abc ~> 123
方案优势
- 完全满足需求:直接调用
foo('abc')返回默认字符串,调用foo('abc').bar('efg')返回带参数的结果 - 结果可直接作为字符串使用,无需额外调用方法或依赖
println输出 - 逻辑清晰,没有冗余代码,符合Groovy动态特性的最佳实践
如果更倾向于结构化实现,也可以用自定义类完成,逻辑类似但更严谨:
class FooResult { private String baseResult FooResult(String aStr) { this.baseResult = "${aStr} ~> 123" } String bar(String bStr) { return "${bStr} : ${baseResult}" } @Override String toString() { return baseResult } } def foo(String aStr) { return new FooResult(aStr) } // 测试调用 println foo('abc') // abc ~> 123 println foo('abc').bar('efg') // efg : abc ~> 123
内容的提问来源于stack exchange,提问作者Marslo
相关产品推荐
相关产品推荐

