我目前正在实施迭代求解器,它通过连续改进对特定问题的解决方案的估计来工作。由于解决方案是一组相当大的数据,因此可以进行细化。
我已经实现了一个简单的Observer / Observable模式,以便能够在迭代发生时观察算法。特别是,求解器提供了一种方法
Foo getCurrentSolution()
返回解决方案的当前估计值。然后,观察者可以根据当前估计自由地进行一些计算(例如:确定解决方案是否足够好并且可以停止迭代)。 Foo
是可变的,但当然,如果观察者修改了解的当前估计值,这可能会破坏求解器的迭代。
因此,getCurrentSolution()
应该真正返回防御性副本。但这需要大量问题的时间和记忆,所以我提出了另一个想法,即让getCurrentSolution()
返回一个新的ReadOnlyFoo(bar)
,其中foo
是(可变的)当前估计值解决方案,对求解器是私有的。我们的想法是ReadOnlyFoo
具有与Foo
几乎相同的接口,只有可能修改数据的方法被“停用”(它们抛出异常)。下面给出了一些虚拟类的所有细节。
我的问题是:这种方法是好的做法吗?有更好的模式吗?
谢谢! 的Sebastien
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");
}
}
答案 0 :(得分:3)
我将定义一个仅包含只读方法的接口Solution
和一个包含所有方法的可变类MutableSolution
,并使getCurrentSolution()
方法返回{{1}实例。这样,您无需创建防御性副本或将解决方案包装到只读包装器中。
当然,观察者仍然可以将解决方案转换为Solution
,但这不是偶然的。如果你想保护自己免受强制转换,那么写一个实现MutableSolution
的{{1}}包装器类并委托给包裹的ReadOnlySolution
。这类似于你的命题,除了方法的签名清楚表明对象不可变。
答案 1 :(得分:1)
这实际上是Collections
类对unmodifiableList(...)
等做的方法。它返回一个包含原始列表的包装器,但在修改集合的方法中抛出异常。
答案 2 :(得分:1)
我不会这样做。如果使用AbstractFoo
甚至一个公共接口(可能存在于您的实际实现中),那么他事先并不知道当前实例是否可变。因此,用户将冒一些未经检查的异常的风险。
而且,对于一个不可改变的对象,它是不可修改的,它根本不是特例。换句话说:我不会使用execption来发信号,那个人试图修改FooReadOnly
的实例。
至少我将抽象方法boolean isModifiable()
添加到抽象类AbstractFoo
,以便我们可以测试,如果我们可以修改对象。在这种情况下,我们不需要抛出异常 - 修改方法的实现可能什么也不做。
答案 3 :(得分:0)
为什么这种过度设计的解决方案?为什么没有一个类和readOnly布尔属性?然后为每个setter执行checkWriteable()。