ジェネリック型の消去とインターフェイス宣言の重複により、以下のクラス定義をコンパイルできないため、これを1つのクラスで直接行うことはできません。
class TwoTypesConsumer implements Consumer<Apple>, Consumer<Tomato> {
// cannot compile
...
}
同じ消費操作を1つのクラスにパックする他のソリューションでは、クラスを次のように定義する必要があります。
class TwoTypesConsumer { ... }
両方の操作の定義を繰り返す/複製する必要があり、インターフェースから参照されないので、これは無意味です。これを行う私見は、私が回避しようとしている悪い小さなコードの重複です。
これは、1つのクラスで2つの異なるオブジェクト(結合されていない場合)を使用する責任が多すぎることも示している可能性があります。
しかし、私がやっていることは、明示的なファクトリオブジェクトを追加して、次の方法で接続されたコンシューマを作成することです。
interface ConsumerFactory {
Consumer<Apple> createAppleConsumer();
Consumer<Tomato> createTomatoConsumer();
}
実際にこれらのタイプが本当に関連している(関連している)場合は、そのような方法で実装を作成することをお勧めします。
class TwoTypesConsumerFactory {
// shared objects goes here
private class TomatoConsumer implements Consumer<Tomato> {
public void consume(Tomato tomato) {
// you can access shared objects here
}
}
private class AppleConsumer implements Consumer<Apple> {
public void consume(Apple apple) {
// you can access shared objects here
}
}
// It is really important to return generic Consumer<Apple> here
// instead of AppleConsumer. The classes should be rather private.
public Consumer<Apple> createAppleConsumer() {
return new AppleConsumer();
}
// ...and the same here
public Consumer<Tomato> createTomatoConsumer() {
return new TomatoConsumer();
}
}
利点は、ファクトリクラスが両方の実装を認識し、共有状態があり(必要な場合)、必要に応じてより多くの結合されたコンシューマを返すことができることです。インターフェースから派生していない繰り返しの消費メソッド宣言はありません。
それらが完全に関連していない場合、各コンシューマは独立した(まだプライベート)クラスである可能性があることに注意してください。
そのソリューションの欠点は、クラスが複雑になること(これが1つのJavaファイルである場合でも)で、消費メソッドにアクセスするには、次の代わりにもう1回呼び出す必要があります。
twoTypesConsumer.consume(apple)
twoTypesConsumer.consume(tomato)
あなたが持っている:
twoTypesConsumerFactory.createAppleConsumer().consume(apple);
twoTypesConsumerFactory.createTomatoConsumer().consume(tomato);
要約すると、 2つの内部クラスを使用して1つの最上位クラスで2つの汎用コンシューマを定義できますが、呼び出しの場合は、適切な実装コンシューマへの参照を最初に取得する必要があります。これは単なる1つのコンシューマオブジェクトではないためです。