2

私が抱えている問題は、すでに以前に尋ねられています:インターフェイスが Comparable を拡張する列挙型を使用してインターフェイスを実装する方法は?

ただし、どのソリューションも私の正確な問題を解決するものではありません。これは次のとおりです。

に似た値オブジェクトがありますBigDecimal。この値は、実際のオブジェクトでは設定されないことがあります。これは、その値がまだわかっていないためです。したがって、 Null オブジェクト パターンを使用して、このオブジェクトが定義されていない時間を表現したいと考えています。ComparableNull オブジェクトにインターフェイスを実装させようとするまでは、これは問題ではありません。説明する 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ますが、それのインスタンスが1つだけであることを保証することはできません。つまり、Effective Java Item 3、pg。17-18
4

3 に答える 3

2

NullObject パターンはお勧めしません。私は常に次の 2 つの状況のいずれかに陥っているためです。

  • オブジェクトのように NullObject を使用するのは意味がなく、そのままにしておく必要がありますnull
  • NullObject は単なる NullObject であるにはあまりにも多くの意味を持ち、それ自体が真のオブジェクトであるべきです (たとえば、完全に機能するデフォルト値のように振る舞う場合)。

コメントでの議論によると、NullObject は通常のオブジェクトの値 0 と非常によく似ているように思えます。

私がすることは、実際には 0 (またはより意味のあるデフォルト値) を使用し、初期化されているかどうかを本当に知る必要がある場合はフラグを立てることです。このように、次の 2 つの点を考慮する必要があります。

  • すべての初期化されていない値は、ソリューションと同じインスタンスを共有しません
  • まったく同じ理由で、新しいインスタンスを作成することなく、後でオブジェクトを初期化できるようになりました

これが私が考えるコードの種類です:

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;
    }
}
于 2014-04-23T15:11:48.760 に答える
1

あなたが示唆したように、1つの解決策は、列挙型の代わりにクラスを使用することだと思います:

public class NullFoo implements Foo {

    private NullFoo() {
    }

    public static final Foo INSTANCE = new NullFoo();

    @Override
    public int compareTo(Foo f) {
        return f == this ? 0 : -1;
    }

    @Override
    public int getValue() {
        return 0;
    }

}

これは列挙型の動作を模倣していますが、Foo インターフェースを実装できます。プライベート コンストラクターのため、クラスはインスタンス化できません。そのため、使用可能な唯一のインスタンスは、 (修飾子NullFoo.INSTANCEのおかげで) スレッド セーフである を介してアクセスできるインスタンスです。final

于 2014-04-23T15:06:14.943 に答える