之前已经问过我遇到的问题:How to implement an interface with an enum, where the interface extends Comparable?
但是,没有一种解决方案可以解决我的确切问题,这是:
我有一个值对象,类似于BigDecimal
。有时,此值将不会用实际对象设置,因为尚不知道该值。因此,我想使用Null Object Pattern表示未定义此对象的时间。直到我尝试使我的Null对象实现Comparable
接口之前,这都不是问题。这是一个SSCCE来说明:
public class ComparableEnumHarness {
public static interface Foo extends Comparable<Foo> {
int getValue();
}
public static class VerySimpleFoo implements Foo {
private final int value;
public VerySimpleFoo(int value) {
this.value = value;
}
@Override
public int compareTo(Foo f) {
return Integer.valueOf(value).compareTo(f.getValue());
}
@Override
public int getValue() {
return value;
}
}
// Error is in the following line:
// The interface Comparable cannot be implemented more than once with different arguments:
// Comparable<ComparableEnumHarness.NullFoo> and Comparable<ComparableEnumHarness.Foo>
public static enum NullFoo implements Foo {
INSTANCE;
@Override
public int compareTo(Foo f) {
return f == this ? 0 : -1; // NullFoo is less than everything except itself
}
@Override
public int getValue() {
return Integer.MIN_VALUE;
}
}
}
其他问题:
在真实的示例中,这里有我称为
Foo
的多个子类。我可以通过使
NullFoo
不是enum
来解决此问题,但是我不能保证永远只有一个实例,即Effective Java Item 3, pg. 17-18 最佳答案
我不建议使用NullObject模式,因为我总是处于以下两种情况之一:
像对象一样使用NullObject是没有意义的,应该保留null
NullObject具有太多的含义,不能仅仅是一个NullObject,而应该本身就是一个真实的对象(例如,当它充当功能齐全的默认值时)
根据我们在评论中的讨论,在我看来,您的NullObject的行为与正常对象的0值非常相似。
我要做的实际上是使用0(或更有意义的默认值),如果您确实需要知道它是否已初始化,请放置一个标志。这样,您将需要考虑两件事:
所有未初始化的值都不会与我的解决方案共享同一实例
由于同样的原因,您现在可以稍后在不创建新实例的情况下初始化对象
这是我想到的那种代码:
public static class VerySimpleFoo implements Foo {
private int value;
private boolean initialized;
public VerySimpleFoo() {
this.value = 0; // whatever default value makes more sense
this.initialized = false;
}
public VerySimpleFoo(int value) {
this.value = value;
this.initialized = true;
}
@Override
public int compareTo(Foo f) {
// possibly need some distinction here, depending on your default value
// and the behavior you expect
return Integer.valueOf(value).compareTo(f.getValue());
}
@Override
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
this.initialized = true;
}
public boolean isInitialized() {
return initialized;
}
}