2つのインターフェースがあり、どちらも目的がまったく異なりますが、メソッドの署名が同じである場合、両方のインターフェースに役立つ単一のメソッドを記述したり、メソッドに複雑なロジックを記述したりせずに、クラスに両方を実装させるにはどうすればよいですか?呼び出しが行われているオブジェクトのタイプをチェックし、適切なコードを呼び出す実装?
C#では、これは明示的なインターフェイス実装と呼ばれるものによって克服されます。Javaに同等の方法はありますか?
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.
}
あなたができることは、それぞれが異なるインターフェースを実装する2つのクラスからクラスを構成することです。その場合、その1つのクラスは両方のインターフェースの動作を持ちます。
class CompositeClass {
ISomething class1;
ISomething2 class2;
void doSomething1(){class1.doSomething();}
void doSomething2(){class2.doSomething();}
}
ISomething1 CompositeClass.asInterface1();
とISomething2 CompositeClass.asInterface2();
、そのクラスにメソッドを。次に、複合クラスからどちらか一方を取得できます。ただし、この問題に対する優れた解決策はありません。
public long getCountAsLong() implements interface2.getCount {...}
[場合には、インターフェイスが必要ですlong
が、クラスのユーザーが期待するint
]またはprivate void AddStub(T newObj) implements coolectionInterface.Add
[想定しcollectionInterface
ているcanAdd()
方法を、このクラスのすべてのインスタンスのためにそれを返しますかfalse
]?
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
withのサブインターフェイスを作成できますBeta asBeta()
。
この問題が発生している場合は、委任を使用する必要がある場所で継承を使用している可能性があります。同じ基になるデータモデルに対して、類似しているものの2つの異なるインターフェイスを提供する必要がある場合は、ビューを使用して、他のインターフェイスを使用してデータへのアクセスを安価に提供する必要があります。
後者の場合の具体的な例を示すために、Collection
とMyCollection
(から継承せずCollection
、互換性のないインターフェイスを持つ)の両方を実装するとします。同じ基になるデータを使用して、との軽量実装を提供するCollection getCollectionView()
とMyCollection getMyCollectionView()
関数を提供できます。Collection
MyCollection
前者の場合...整数の配列と文字列の配列が本当に必要だとします。List<Integer>
との両方から継承する代わりにList<String>
、タイプの1つのメンバーとタイプのList<Integer>
別のメンバーList<String>
を用意し、両方から継承しようとするのではなく、それらのメンバーを参照する必要があります。整数のリストのみが必要な場合でも、この場合は継承よりも構成/委任を使用することをお勧めします。
「古典的な」Javaの問題も私のAndroid開発に影響を与えます...
理由は単純なようです:
使用する必要のあるフレームワーク/ライブラリが増えると、物事が制御不能になる可能性が高くなります...
私の場合、BootStrapperAppクラスがあります継承android.app.Application、
同じクラスでも実装する必要があり、一方、プラットフォーム集積得るためにMVVMフレームワークのインタフェースを。
メソッドの衝突はgetString()メソッドで発生しました。これは両方のインターフェイスによってアナウンスされ、異なるコンテキストで異なる実装が必要です。
回避策(醜い..IMO)は、内部クラスを使用してすべてのプラットフォームを実装していますメソッド、1つのマイナーなメソッドシグネチャの競合のために...場合によっては、そのような借用されたメソッドはまったく使用されません(ただし、主要な設計セマンティクスに影響します)。
私は、C#スタイルの明示的なコンテキスト/名前空間の表示が役立つことに同意する傾向があります。
私の頭に浮かんだ唯一の解決策は、複数のインターフェースを強制したいオブジェクトへの参照オブジェクトを使用することです。
例:実装するインターフェースが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 *メソッドを使用してクラスを「公開」できるようになりました
問題のすべてのコードを完全に制御でき、これを事前に実装できれば、すべてうまくいきます。ここで、メソッドを使用して多くの場所で使用されている既存のパブリッククラスがあると想像してください。
public class MyClass{
private String name;
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
次に、WBPInterfaceを実装するためのクラスを必要とする既製のWizzBangProcessorに渡す必要があります...これにはgetName()メソッドもありますが、具体的な実装の代わりに、このインターフェイスはメソッドが型の名前を返すことを期待していますウィズバン処理の。
C#ではそれは些細なことです
public class MyClass : WBPInterface{
private String name;
String WBPInterface.getName(){
return "MyWizzBangProcessor";
}
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
Java Toughでは、既存のデプロイ済みコードベースで、あるインターフェイスから別のインターフェイスに変換する必要があるすべてのポイントを特定する必要があります。確かに、WizzBangProcessor会社はgetWizzBangProcessName()を使用する必要がありましたが、彼らも開発者です。彼らの文脈では、getNameは問題ありませんでした。実際、Java以外では、他のほとんどのOOベースの言語がこれをサポートしています。Javaは、すべてのインターフェースを同じメソッドNAMEで実装することを強制することはまれです。
他のほとんどの言語には、「この実装されたインターフェイスのこのメソッドのシグネチャに一致するこのクラスのこのメソッドは、その実装です」という命令を喜んで受け取るコンパイラがあります。結局のところ、インターフェースを定義することの全体的なポイントは、定義を実装から抽象化できるようにすることです。(JavaのInterfacesでデフォルトのメソッドを使用することを始めないでください。デフォルトのオーバーライドは言うまでもありません。確かに、ロードカー用に設計されたすべてのコンポーネントは、空飛ぶ車にぶつかって動作するはずです。どちらも車です...車はヨーイングするだけなので、デフォルトのピッチとロールの入力では、衛星ナビゲーションのデフォルト機能は影響を受けないと確信しています。