首页 > 解决方案 > 具有状态 Groovy / Java 的方法

问题描述

我有一个冗长的问题。假设我有一个进行数学计算的方法,并且该方法需要保持状态(即,每次使用参数调用它时,其结果都会受到其先前结果的影响)。

int sum

def add(int x, int y) {
 sum = sum + x + y
 return sum
}

最重要的是,它的状态取决于它被调用的位置。(即,如果我从不同的地方两次调用此方法,则该方法必须仅适用于它自己的状态)。我在考虑 groovy 中的闭包,但闭包不会保持状态,如果您将状态存储在闭包之外的变量中,则对该方法的第二次调用将不会有自己的状态。

让我们还假设由于我现在不会进入的原因,我不能将此方法保留在对象中以保持状态。IE

class MyObject {
   private int sum

   MyObject() {}

   public int sum(int x, int y) {
     sum = sum + x + y
     return sum
  }
}

我想避免这样做

MyObject mObj = new MyObject()
.... some code later
def result = mObj.add(1,2)

相反,我只想这样做

for (int i = 0; i<5;i++){
    def result1 = add(1,2)
}
some code later
for (int i = 0; i<5;i++){
    def result2 = add(1,2)
}

在上述情况下,两个“添加”方法应该有自己的状态。

groovy 或 java 中是否还有其他技巧可以实现这样的目标?

标签: javagroovy

解决方案


你在这里描述的是一个闭包。那里的 Groovy 代码已经做到了。如果您想将该“全局”状态放入函数中,您可以明确说明并“构建”该add函数。例如

def add = { ->
    def total = 0
    return { a, b -> 
        return total += a + b 
    }
}()

println(add(1,2))
// -> 3
println(add(1,2))
// -> 6
println(add(1,2))
// -> 9

上面的代码创建了一个函数,它保存状态total并返回一个闭包,它执行实际的添加。它捕获本地 total. 然后调用此函数并将结果(闭包)分配给add.

编辑

如评论中所述,期望是一个“魔术”边界,用于隔离add程序执行过程中的状态。假设这个问题是针对 DSL 的,用户可能能够知道隐含的边界。但是我怀疑 Groovy(或 Java?)是否有办法知道,除非您编写自己的 for,否则从 for 循环内部调用函数。

解决这个问题的一种方法是创建一个像这样的显式边界:

def withTotal(c) {
    def total = 0
    c.add = { total += it }
    c.call()
    total
}

println withTotal{
    add(1)
    add(2)
}
// -> 3

println withTotal{
    10.times{ add it }
}
// -> 45

推荐阅读