4

緩く型付けされたオブジェクト (JavaScript など) として動作するクラス (または同じインターフェイスを実装するクラスのセット) を定義しようとしています。それらはあらゆる種類のデータを保持でき、それらに対する操作は基になる型に依存します。

私はそれを 3 つの異なる方法で動作させていますが、理想的な方法はありません。これらのテスト バージョンでは、文字列と整数のみが許可され、唯一の操作は追加です。整数を追加すると整数値の合計になり、文字列を追加すると文字列が連結され、整数を文字列に追加すると整数が文字列に変換され、文字列と連結されます。最終バージョンには、より多くの型 (Double、Array、新しいプロパティを動的に追加できる JavaScript のようなオブジェクト) とより多くの操作が含まれます。

方法 1:

public interface DynObject1 {
  @Override public String toString();
  public DynObject1 add(DynObject1 d);
  public DynObject1 addTo(DynInteger1 d);
  public DynObject1 addTo(DynString1 d);
}


public class DynInteger1 implements DynObject1 {
  private int value;

  public DynInteger1(int v) {
    value = v;
  }

  @Override
  public String toString() {
    return Integer.toString(value);
  }

  public DynObject1 add(DynObject1 d) {
    return d.addTo(this);
  }

  public DynObject1 addTo(DynInteger1 d) {
    return new DynInteger1(d.value + value);
  }

  public DynObject1 addTo(DynString1 d)
  {
    return new DynString1(d.toString()+Integer.toString(value));
  }
}

...DynString1 についても同様

方法 2: public interface DynObject2 { @Override public String toString(); public DynObject2 add(DynObject2 d); }

public class DynInteger2 implements DynObject2 {
  private int value;

  public DynInteger2(int v) {
    value = v;
  }

  @Override
  public String toString() {
    return Integer.toString(value);
  }

  public DynObject2 add(DynObject2 d) {
    Class c = d.getClass();

    if(c==DynInteger2.class)
    {
      return new DynInteger2(value + ((DynInteger2)d).value);
    }
    else
    {
      return new DynString2(toString() + d.toString());
    }
  }
}

...DynString2 についても同様

方法 3:

public class DynObject3 {

  private enum ObjectType {
    Integer,
    String
  };

  Object value;
  ObjectType type;

  public DynObject3(Integer v) {
    value = v;
    type = ObjectType.Integer;
  }

  public DynObject3(String v) {
    value = v;
    type = ObjectType.String;
  }

  @Override
  public String toString() {
    return value.toString();
  }

  public DynObject3 add(DynObject3 d)
  {
    if(type==ObjectType.Integer && d.type==ObjectType.Integer)
    {
      return new DynObject3(Integer.valueOf(((Integer)value).intValue()+((Integer)value).intValue()));
    }
    else
    {
      return new DynObject3(value.toString()+d.value.toString());
    }
  }
}

if-else ロジックを使用すると、型を格納する代わりに value.getClass()==Integer.class を使用できますが、より多くの型を使用すると、これを変更して switch ステートメントを使用し、Java では switch でクラスを使用できません。

とにかく...私の質問は、これを行うための最良の方法は何ですか?

4

2 に答える 2

2

あなたがやろうとしていることは、ダブルディスパッチと呼ばれています。呼び出されるメソッドは、呼び出されるオブジェクトの実行時型と、その引数の実行時型の両方に依存する必要があります。

Javaおよびその他のC派生物は、単一ディスパッチのみをサポートします。そのため、オプション1で使用したビジターパターンのような応急修理が必要です。これは、これを実装する一般的な方法です。反射を使用しないため、この方法をお勧めします。さらに、ディスパッチを実行するための大きな「スイッチボード」メソッドを必要とせずに、各ケースを独自のメソッドに保持できます。

于 2010-05-07T06:47:46.853 に答える
0

2番目のオプションを選択します。3番目のオプションでは、ジェネリックを使用して、その列挙型に依存しないようにすることをお勧めします。そして、最初のオプションを使用すると、残りの人生のメソッドを実装することができます。とにかく、クラスマッチングに「instanceof」演算子を使用できます。

于 2010-05-07T06:48:19.153 に答える