web-dev-qa-db-ja.com

複数のインターフェースのプリジェネリックを実装するパラメーターの使用

私がこれらのインターフェースを持っているとしましょう:

_public interface I1 {
  void foo();
}

public interface I2 {
  void bar();
}
_

そしてクラス:

_public class A extends AParent implements I1, I2 {
   // code for foo and bar methods here
}

public class B extends BParent implements I1, I2 {
  // code for foo and bar methods here
}

public class C extends CParent implements I1 {
  // code for foo method here
}
_

今、ジェネリックで私は次のようなメソッドを持つことができます:

_public <T extends I1 & I2> void method(T param) {
  param.foo();
  param.bar();
}
_

aとBの両方をパラメーターとして使用して呼び出すことはできますが、Cを使用して呼び出すことはできません(I2を実装していません)。

このタイプのタイプセーフプレジェネリック(Java <1.5)を実現する方法はありましたか?.

A、B、Cには異なる継承ツリーがあり、AParentやBParentのように自分自身に共通の親を持つことは実際にはオプションではないことを考慮してください。

私はあなたができることを知っています:

_public void method(I1 param) {
  param.foo();
  ((I2)param).bar();
}
_

しかし、I2を実装していないmethod(new C())を呼び出すこともできるため、問題が発生します。

これを行う方法は他にありますか?

追伸:私は本当にこれをする必要はありません、私が尋ねるのは、たいてい好奇心からです。

35

I3がI1とI2を拡張する3番目のインターフェースを作成します。次に、クラスAとBの両方がI3を実装し、ジェネリックメソッドはI3を受け入れます。

それはおそらくそれを行う唯一の方法です。

26

上記の答えはデザインの観点からは良いとは思いません。インターフェイスを作成するときは、そのインターフェイスで定義されている一部のアクションについて、呼び出し元オブジェクトにresponsibilityが含まれていることを確認する必要があります。したがって、上記で説明している2つのソリューションがあり、それらのソリューションがデザインの観点から良くない理由を説明します。

1。1つのインターフェースが2つのインターフェースの両方を拡張するようにする:

public interface IC extends IA,IB {
   // empty method here
}

上記のコードは無意味です。別のインターフェースを定義して、他のインターフェースを組み合わせるだけで、内部には新しいメソッドはありません。 2つのインターフェースICIAを組み合わせる代わりに、IBに値を追加しません。また、状況によっては、この方法を使用すると、3番目のインターフェースに適した名前が見つからないときにコードが「少し面白く」なります。この状況は、IReadableAndWriteableISomethingAndSomethingAndAnotherThingなどのインターフェース名につながります

2。メソッド内の型キャスト:

public void methodA(IA object) {
   if (object instance of IB) {
     ((IB)(object)).someMethod()
}

この方法もナンセンスです。入力パラメーターがIAである理由は、インターフェイスIBから何らかのアクションを実行する必要がありますか?プログラマーの視点では、ドキュメントを読む以外にそれを知る方法はありません。他の人が使用する関数を設計するのは良くありません。

真の解:

上記の解決策には、設計に別の問題があります。あなたはforceプログラマーが2つのインターフェースを担当する1つのオブジェクトを使用します。プログラマがこれを実行したくない場合の問題は何ですか。彼らは、簡単なテスト、クリーンなコードのために、異なるインターフェイスごとに2つの異なる具象クラスを使用したいですか? できません。

メソッドシグネチャで2つの異なるパラメータを作成する必要があります。

public void exampleMethod(IA object1, IB object2) {
   object1.someMethod()
   object2.someMethod()
}

上記のメソッドを呼び出すには、同じパラメータを内部に配置します(プログラマが同じオブジェクトを使用する場合)。彼らはまた、異なるオブジェクトを置くこともできます。

public void caller() {
   IC object3 = new C(); // C is the class implements both IA and IB
   exampleMethod(object3, object3);
   IA objectA = new A();
   IB objectB = new B();
   exampleMethod(objectA, objectB);       
}

この助けを願っています:)

13
hqt

sri は、AとBの署名を変更する権限がある場合に最適です。ただし、権限がない場合は、次のようにすることができます。

public void method(I1 param1 , I2 param2) { // unpopular classes that do not implement I3 must use this method
  param1.foo();
  param2.bar();
}
public void method(I3 param){ // I hope everybody implements I3 when appropriate
  param.foo();
  param.bar();
}
public void method(A param){// A is a popular class
  method(param,param);
}
public void method(B param){// B is a popular class
  method(param,param);
}

もちろん、今はジェネリックを使用するだけです。

2
emory

Java 1.5以前は、IMOにはコンパイル時にそのような型の安全を達成するための解決策はありませんでした。しかし、 "instanceof"を使用して実行時に魂が存在します。

public void method(Object o) {
  if (!(o instanceof I1))
    throw new RuntimeException("o is not instance of I1");

  if (!(o instanceof I2))
    throw new RuntimeException("o is not instance of I2");

  // go ahead ...
}
2
BraincompilerLC