Java - インターフェース実装におけるメソッド名の衝突
-
25-09-2019 - |
質問
2 つのインターフェイスがあり、どちらも目的はまったく異なりますが、メソッド シグネチャが同じである場合、両方のインターフェイスに機能する単一のメソッドを作成したり、メソッド内に複雑なロジックを記述したりすることなく、クラスに両方を実装するにはどうすればよいですか?呼び出しが行われているオブジェクトのタイプをチェックし、適切なコードを呼び出す実装?
C# では、これはいわゆる明示的なインターフェイス実装によって克服されます。Javaに同等の方法はありますか?
解決
いいえ、Javaで1クラスに2つの異なる方法で同じメソッドを実装する方法はありません。
これは、Javaがそれを禁止している理由である多くの混乱状況につながることができます。
interface ISomething {
void doSomething();
}
interface ISomething2 {
void doSomething();
}
class Impl implements ISomething, ISomething2 {
void doSomething() {} // There can only be one implementation of this method.
}
あなたはどうすることができますことは、それぞれが異なるインタフェースを実装することを二つのクラスのクラスを構成しています。そして、その1つのクラスは、両方のインターフェイスの動作を持っています。
class CompositeClass {
ISomething class1;
ISomething2 class2;
void doSomething1(){class1.doSomething();}
void doSomething2(){class2.doSomething();}
}
他のヒント
Javaでこれを解決する本当の方法はありません。あなたは、回避策として、内部クラスを使用することができます:
interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
private int value;
public void m() { ++value; } // Alfa.m()
public Beta asBeta() {
return new Beta(){
public void m() { --value; } // Beta.m()
};
}
}
それはAlfaBeta
からBeta
へのキャストはできませんが、ダウンキャストは、一般的に悪であり、それはAlfa
インスタンスは、多くの場合、あまりにも、Beta
の側面を持っていることを期待することができれば、といくつかの理由で(通常の最適化にのみ有効ですその理由)あなたはBeta
に変換することができるようにしたい、あなたはそれにAlfa
とBeta asBeta()
のサブインタフェースを作ることができます。
この問題が発生した場合は、次のことを使用している可能性があります。 継承 どこで使用すべきか 代表団. 。同じ基礎となるデータ モデルに対して、類似しているにもかかわらず 2 つの異なるインターフェイスを提供する必要がある場合は、 ビュー 他のインターフェイスを使用してデータへのアクセスを安価に提供します。
後者の具体例として、両方を実装するとします。 Collection
そして MyCollection
(これは継承しません Collection
互換性のないインターフェースを持っています)。提供できるのは、 Collection getCollectionView()
そして MyCollection getMyCollectionView()
の軽量実装を提供する関数 Collection
そして MyCollection
, 、同じ基礎となるデータを使用します。
前者の場合は…本当に整数の配列と文字列の配列が必要だとします。両方から継承するのではなく、 List<Integer>
そして List<String>
, 、次のタイプのメンバーが 1 つ必要です。 List<Integer>
およびタイプの別のメンバー List<String>
, 、両方から継承しようとするのではなく、それらのメンバーを参照します。整数のリストのみが必要な場合でも、この場合は継承ではなく合成/委任を使用する方が良いでしょう。
「古典」Javaの問題がまた私のAndroidの開発に影響を与えます...
理由は簡単であるように思わ:
あなたは物事が制御不能にすることができ、より簡単に、使用する必要があり、よりフレームワーク/ライブラリ...
私の場合、私は、の のandroid.app.Application のを、
から継承されたの のBootStrapperApp ののクラスを持っています
一方、同じクラスにも統合を取得するために、MVVMフレームワークのの のプラットフォームののインタフェースを実装する必要があります。
メソッドの衝突は、両方のインターフェイスが発表され、異なるコンテキストで相違が実装しなければならないの ののgetString()のの方法、発生しました。
この問題を回避する(ugly..IMO)は、すべてのプラットフォームの方法は、という理由だけで1つのマイナーメソッドシグネチャが競合する...いくつかの場合には、そのような借用方法をも全く使用されない実装するために内部クラスを使用しています(しかし、主要な設計のセマンティクスに影響を与えた)。
私は#スタイルの明示的なコンテキスト/名前空間の表示が便利ですCを同意する傾向がある。
私の心に来た唯一の解決策は、あなたがimplent muliple interfacecesにしたいものにrefereceオブジェクトを使用しています。
例:あなたは
を実装するための2つのインタフェースを持っていると仮定public interface Framework1Interface {
void method(Object o);
}
と
public interface Framework2Interface {
void method(Object o);
}
あなたは2つのFacadorオブジェクトにそれらを囲むことができます:
public class Facador1 implements Framework1Interface {
private final ObjectToUse reference;
public static Framework1Interface Create(ObjectToUse ref) {
return new Facador1(ref);
}
private Facador1(ObjectToUse refObject) {
this.reference = refObject;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Framework1Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}
@Override
public void method(Object o) {
reference.methodForFrameWork1(o);
}
}
と
public class Facador2 implements Framework2Interface {
private final ObjectToUse reference;
public static Framework2Interface Create(ObjectToUse ref) {
return new Facador2(ref);
}
private Facador2(ObjectToUse refObject) {
this.reference = refObject;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Framework2Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}
@Override
public void method(Object o) {
reference.methodForFrameWork2(o);
}
}
最後にクラスを使用すると、望んでいたはずのような何か。
public class ObjectToUse {
private Framework1Interface facFramework1Interface;
private Framework2Interface facFramework2Interface;
public ObjectToUse() {
}
public Framework1Interface getAsFramework1Interface() {
if (facFramework1Interface == null) {
facFramework1Interface = Facador1.Create(this);
}
return facFramework1Interface;
}
public Framework2Interface getAsFramework2Interface() {
if (facFramework2Interface == null) {
facFramework2Interface = Facador2.Create(this);
}
return facFramework2Interface;
}
public void methodForFrameWork1(Object o) {
}
public void methodForFrameWork2(Object o) {
}
}
あなたは今、あなたのクラスを「公開」
へのGetAs *メソッドを使用することができますあなたはこれらの作業を行うために、アダプタのパターンを使用することができます。各インターフェイスのための2つのアダプタを作成し、それを使用しています。それは問題を解決する必要があります。
すべてうまくといいますが、問題のコードの全てを完全に制御を持っており、この先行を実装することができるとき。 今、あなたはこの方法で多くの場所で使用される既存のパブリッククラスを持っている想像
public class MyClass{
private String name;
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
今、あなたはまたのgetName()メソッドを持っている... WBPInterfaceを実装するクラスを必要と棚WizzBangProcessorオフにそれを渡す必要があるが、代わりにあなたの具体的な実装で、このインタフェースは、メソッドが名前を返すことを期待します小便バン処理の種類のます。
でC#が、それはtrvial
になりますpublic class MyClass : WBPInterface{
private String name;
String WBPInterface.getName(){
return "MyWizzBangProcessor";
}
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
でJavaは、あなたが他の1つのインターフェースから変換する必要があり、既存の展開のコードベース内のすべてのポイントを特定する必要があるとしている厳しいです。確かにWizzBangProcessor会社はgetWizzBangProcessNameを()を使用している必要がありますが、彼らはあまりにも開発されています。そのコンテキスト内のgetNameは大丈夫でした。実際には、Javaの外は、他のほとんどのオブジェクト指向ベースの言語はこれをサポートしています。 Javaは、同じメソッド名を使用して実施されるすべてのインタフェースを強制的に稀です。
他のほとんどの言語は、「この実装されたインタフェースでは、このメソッドのシグネチャと一致し、このクラスでは、この方法は、それの実装である」と言う指示を取ることより幸せであるコンパイラを持っています。インターフェイスを定義するすべての全体のポイントの後に定義が実装から抽象化されるようにすることです。ちょっと - 確かに、道路の車のために設計されたすべてのコンポーネントが空飛ぶ車、ちょうど仕事に激突得ることができる必要がありますので(Doがさえ....オーバーライドだけではデフォルトを聞かせて、私は、Javaのインタフェースのデフォルトのメソッドを持つに始めるありません彼らは両方の車です...私は確かに車は唯一のヨーので、あなたの土ナビゲーションバーは、デフォルトピッチとロール入力で影響されることはありません言う!
のデフォルトの機能です