web-dev-qa-db-ja.com

Java-インターフェース実装でのメソッド名の衝突

目的がまったく異なるが、同じメソッドシグネチャを持つ2つのインターフェイスがある場合、両方のインターフェイスに役立つ単一のメソッドを記述せず、メソッドに複雑なロジックを記述することなく、クラスに両方を実装するにはどうすればよいですか呼び出しが行われているオブジェクトのタイプをチェックし、適切なコードを呼び出す実装?

C#では、これは明示的なインターフェイス実装と呼ばれるものによって克服されます。 Java?

85
Bhaskar

いいえ、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.
}

できることは、それぞれが異なるインターフェースを実装する2つのクラスからクラスを構成することです。その場合、その1つのクラスは両方のインターフェースの動作を持ちます。

class CompositeClass {
    ISomething class1;
    ISomething2 class2;
    void doSomething1(){class1.doSomething();}
    void doSomething2(){class2.doSomething();}
}
73
jjnguy

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()で。

13
gustafc

この問題が発生している場合は、おそらく使用しているためです 継承 使用する場所 代表団。同じ基礎となるデータモデルに2つの異なるインターフェイスを提供する必要がある場合は、同様のインターフェイスを使用する必要があります。 見る 他のインターフェイスを使用してデータへのアクセスを安価に提供するため。

後者の場合の具体例を示すために、CollectionMyCollectionCollectionを継承せず、互換性のないインターフェースを持っている)の両方を実装するとします。同じ基になるデータを使用して、CollectionおよびMyCollectionの軽量実装を提供するCollection getCollectionView()およびMyCollection getMyCollectionView()関数を提供できます。

前者の場合...整数の配列と文字列の配列が本当に必要だとします。 List<Integer>List<String>の両方から継承する代わりに、List<Integer>型のメンバーとList<String>型の別のメンバーが必要です。これらのメンバーを参照するのではなく、両方から継承します。整数のリストのみが必要な場合でも、この場合は継承よりも合成/委任を使用する方が適切です。

11

「クラシック」Java問題は、私のAndroid開発にも影響します...
理由は簡単なようです:
より多くのフレームワーク/ライブラリを使用する必要があり、より簡単に制御できなくなる可能性があります...

私の場合、BootStrapperAppから継承されたクラスAndroid.app.Application
一方、同じクラスは、統合するためにMVVMフレームワークのPlatformインターフェースも実装する必要があります。
getString()メソッドでメソッドの衝突が発生しました。このメソッドは両方のインターフェースによってアナウンスされ、異なる必要があります異なるコンテキストでの実装。
回避策(ugい..IMO)は、内部クラスを使用してすべてのPlatformメソッドを実装しています。 ...場合によっては、そのような借用された方法はまったく使用されません(ただし、主要な設計セマンティクスに影響します)。
C#スタイルの明示的なコンテキスト/名前空間の表示が役立つことに同意する傾向があります。

1
tiancheng

私の頭に浮かんだ唯一の解決策は、参照オブジェクトを使用して、複数のインターフェイスを実装することです。

例:実装するインターフェースが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 *メソッドを使用してクラスを「公開」できるようになりました

1
notAtAll

これらを機能させるために、アダプタパターンを使用できます。インターフェイスごとに2つのアダプターを作成し、それを使用します。問題を解決するはずです。

0
AlexCon