3

我目前正在实施迭代求解器,它通过不断改进对特定问题的解决方案的估计来工作。由于解决方案是一组相当大的数据,因此进行了适当的细化。

我已经实现了一个简单的 Observer/Observable 模式,以便能够在迭代发生时观察算法。特别是,求解器提供了一种方法

Foo getCurrentSolution()

它返回解决方案的当前估计。然后观察者可以根据当前估计自由地进行一些计算(例如:决定解决方案是否足够好以及是否可以停止迭代)。Foo是可变的,但是当然,如​​果观察者修改了解决方案的当前估计,这可能会破坏求解器的迭代。

所以,getCurrentSolution()真的应该回归防御副本。但这需要时间和内存来解决大问题,所以我想出了另一个想法,即getCurrentSolution()返回一个 new ReadOnlyFoo(bar),其中foo(可变的)当前解决方案估计值是求解器私有的。这个想法是它ReadOnlyFoo具有与 几乎相同的接口Foo,只有可能修改数据的方法被“停用”(它们抛出异常)。下面给出了一些虚拟类的所有细节。

我的问题是:这种方法是好的做法吗?有更好的模式吗?

谢谢!塞巴斯蒂安

public abstract class AbstractFoo{
    public abstract double getValue();

    public abstract void setValue(final double x);

    public abstract AbstractFoo add(AbstractFoo bar);

    public void addToSelf(AbstractFoo bar){
        setValue(getValue + bar.getValue());
    }
}

public class  Foo extends AbstractFoo{
    private double value;

    public Foo(final double x){
        value = x;
    }

    public double getValue(){
        return value;
    }

    public void setValue(final double x){
        value = x;
    }

    public AbstractFoo add(AbstractFoo bar){
        return new Foo(value + bar.getValue());
    }
}

public final class FooReadOnly extends AbstractFoo{
    private final Foo foo;

    public FooReadOnly(AbstractFoo foo){
        this.foo = foo;
    }

    public double getValue(){
        return foo.getValue();
    }

    public void setValue(final double x){
        throw new NotImplementedException("read only object");
    }

    public AbstractFoo add(AbstractFoo bar){
        return foo.add(bar);
    }

    public void addToSelf(AbstractFoo bar){
        throw new NotImplementedException("read only object");
    }
}
4

4 回答 4

3

我将定义一个Solution只包含只读方法的接口和一个MutableSolution包含所有方法的可变类,并使该getCurrentSolution()方法返回一个Solution实例。这样,您无需创建防御性副本或将解决方案包装到只读包装器中。

当然,观察者仍然可以将解决方案转换为 a MutableSolution,但这不是偶然的。如果您想保护自己免受强制转换,请编写一个ReadOnlySolution包装类来实现Solution并委托给被包装的MutableSolution. 这与您的提议类似,只是方法的签名清楚地表明该对象是不可变的。

于 2011-08-11T11:01:03.917 回答
1

这实际上是Collections该类使用unmodifiableList(...)等的方法。它返回一个包含原始列表的包装器,但在修改集合的方法中抛出异常。

于 2011-08-11T10:57:04.293 回答
1

我不会那样做的。如果一个AbstractFoo人甚至使用一个通用接口(可能存在于您的实际实现中),那么他不会提前知道当前实例是否可变。因此,用户将冒着抛出一些未经检查的异常的风险。

而且,对于一个不可变的对象,不可修改的情况一点也不例外。换句话说:我不会使用 execption 来表示有人试图修改FooReadOnly.

至少我会boolean isModifiable()在抽象类 中添加一个抽象方法,AbstractFoo以便我们可以测试,如果我们可以修改对象。在这种情况下,我们不需要抛出异常——修改方法的实现可以简单地什么都不做。

于 2011-08-11T11:02:21.867 回答
0

为什么要做这样一个过度设计的解决方案?为什么没有一个类和只读布尔属性?然后为每个 setter 执行 checkWriteable() 。

于 2012-08-22T12:17:20.470 回答