如何在Groovy中创建类似Grails list()的带闭包多参数方法
实现类似Grails Criteria的带闭包多参数方法
嘿,这个问题我熟!Grails里User.createCriteria().list(){}这种优雅的写法,核心就是Groovy对闭包的特殊语法支持和委托机制。我来一步步教你实现类似的方法:
核心原理
Groovy有个很实用的语法糖:当方法的最后一个参数是闭包时,你可以把闭包移到方法调用的括号外面,这就是那种简洁写法的基础。另外,通过设置闭包的delegate和resolveStrategy,可以让闭包里的方法调用委托给目标对象处理(比如Grails里的Criteria实例)。
完整实现示例
我们来模拟一个简化版的Criteria查询框架,包含支持多参数的list方法:
// 模拟Criteria类,处理查询逻辑和条件 class MockCriteria { // 1. 基础版:仅接受闭包的list方法 def list(Closure closure) { // 将闭包的委托设置为当前Criteria实例 closure.delegate = this // 优先使用委托对象的方法,再用当前上下文 closure.resolveStrategy = Closure.DELEGATE_FIRST // 执行闭包,处理里面的条件(比如eq、like) closure() // 模拟返回查询结果 return ["user_Alice", "user_Bob", "user_Charlie"] } // 2. 多参数版:支持分页、排序等参数,最后一个是闭包 def list(Map params = [:], Closure closure) { // 先处理传入的参数(比如max、offset、sort) println "处理分页参数:max=${params.max}, offset=${params.offset}" println "处理排序参数:sort=${params.sort}, order=${params.order ?: 'ASC'}" // 同样配置闭包的委托策略 closure.delegate = this closure.resolveStrategy = Closure.DELEGATE_FIRST closure() // 模拟根据参数过滤结果 def allResults = ["user_Alice", "user_Bob", "user_Charlie", "user_David", "user_Eve"] if (params.max) { def startIndex = params.offset ?: 0 def endIndex = Math.min(startIndex + params.max, allResults.size()) return allResults.subList(startIndex, endIndex) } return allResults } // 模拟Criteria常用的条件方法 def eq(String property, value) { println "添加查询条件:${property} = ${value}" } def like(String property, value) { println "添加查询条件:${property} LIKE ${value}" } def gt(String property, value) { println "添加查询条件:${property} > ${value}" } } // 模拟User类,提供createCriteria方法 class User { static MockCriteria createCriteria() { return new MockCriteria() } }
调用示例
现在你可以像Grails那样调用这个方法了:
// 调用基础版list方法 def basicUsers = User.createCriteria().list() { eq("active", true) like("email", "%@example.com") } println "基础查询结果:${basicUsers}" // 调用带分页参数的list方法 def paginatedUsers = User.createCriteria().list(max: 2, offset: 1, sort: "username", order: "DESC") { gt("age", 18) } println "分页查询结果:${paginatedUsers}"
关键细节说明
- 闭包的委托设置:
closure.delegate = this和resolveStrategy = Closure.DELEGATE_FIRST是核心,这样闭包里的eq、like等方法会直接调用MockCriteria实例的对应方法,而不是当前上下文的方法。 - 多参数的灵活性:只要保证闭包是方法的最后一个参数,前面可以添加任意类型的参数(比如Map、String、int等),Groovy都会支持把闭包移到括号外的写法。
- 默认参数:给
params设置默认值[:],这样调用时可以不传参数,直接使用闭包写法。
扩展玩法
如果需要更复杂的参数组合,比如同时传入多个非Map参数,只要把闭包放在最后就行:
// 在MockCriteria里添加这个方法 def list(String sortBy, boolean ascending, Closure closure) { println "排序规则:${sortBy} ${ascending ? '升序' : '降序'}" closure.delegate = this closure.resolveStrategy = Closure.DELEGATE_FIRST closure() return ["user_Charlie", "user_Bob", "user_Alice"] } // 调用方式 def sortedUsers = User.createCriteria().list("username", false) { eq("active", true) }
内容的提问来源于stack exchange,提问作者Alireza Khajavi
相关产品推荐
相关产品推荐

