与えられた答えのほとんどは、私たちが継承しようとしているすべてのクラスが私たちによって定義されていることを前提としているようです。
しかし、クラスの1つが私たちによって定義されていない場合、つまり、それらのクラスの1つが継承するものを変更できず、したがって受け入れられた回答を利用できない場合はどうなりますか?
答えは、少なくとも1つのクラスが定義されているかどうかによって異なります。Aつまり、継承したいクラスのリストの中に、A私たちが作成したクラスが存在します。
すでに受け入れられている答えに加えて、この多重継承問題の3つのインスタンスと、それぞれに対する可能な解決策を提案します。
継承タイプ1
Cクラスにクラスを拡張させたいとしましょうA。Bここで、は別の場所で定義されているが、私たちによって定義されてBいるクラスですA。これでできることはA、インターフェースに変換することです。そうすれば、クラスはを拡張しながらC実装できます。AB
class A {}
class B {} // Some external class
class C {}
になる
interface A {}
class AImpl implements A {}
class B {} // Some external class
class C extends B implements A
継承タイプ2
ここで、継承するクラスが3つ以上あるとしましょう。同じ考えが当てはまります。ただし、1つを除くすべてのクラスを定義する必要があります。Aしたがって、クラスが次のクラスから継承するようにしたいとします。 B、、C...XここXで、は外部のクラス、つまり別の場所で定義されたクラスです。他のすべてのクラスを変換するという同じアイデアを適用しますが、最後のクラスをインターフェイスに変換すると、次のようになります。
interface B {}
class BImpl implements B {}
interface C {}
class CImpl implements C {}
...
class X {}
class A extends X implements B, C, ...
継承タイプ3
最後に、継承するクラスがたくさんあるのに、どれも自分で定義していない場合もあります。これは少し注意が必要ですが、委任を利用することで実行できます。委任により、クラスAは他のクラスのふりをすることBができますが、でA定義されたパブリックメソッドへの呼び出しはB、実際にはその型のオブジェクトへの呼び出しを委任しB、結果が返されます。これにより、クラスAは私が呼ぶものになりますFat class
これはどのように役立ちますか?
簡単です。使用する外部クラス内のパブリックメソッドと、作成する新しいクラス内のメソッドを指定するインターフェイスを作成してから、新しいクラスにそのインターフェイスを実装させます。それは紛らわしいように聞こえるかもしれませんので、もっとよく説明させてください。
最初に、次の外部クラス、、、B... 、、がCあり、新しいクラスがそれらすべてのクラスから継承するようにします。DXA
class B {
public void foo() {}
}
class C {
public void bar() {}
}
class D {
public void fooFoo() {}
}
...
class X {
public String fooBar() {}
}
A次に、以前はクラスAにあったパブリックメソッドと、上記のクラスのパブリックメソッドを公開するインターフェイスを作成します。
interface A {
void doSomething(); // previously defined in A
String fooBar(); // from class X
void fooFoo(); // from class D
void bar(); // from class C
void foo(); // from class B
}
最後に、AImplインターフェースを実装するクラスを作成しますA。
class AImpl implements A {
// It needs instances of the other classes, so those should be
// part of the constructor
public AImpl(B b, C c, D d, X x) {}
... // define the methods within the interface
}
そして、あなたはそれを持っています!Aタイプのオブジェクトは、最初に使用した外部クラスの厳密な子孫ではなく、それらのクラスと同じメソッドを定義するインターフェイスを公開するため、これは一種の疑似継承です。
インターフェイスを定義するのではなく、使用したいメソッドを定義するクラスを作成しただけではないのはなぜかと疑問に思われるかもしれません。つまり、継承したいクラスのパブリックメソッドを含むクラスがなかったのはなぜですか?Aこれは、結合を減らすために行われます。A(クラスは大きく変化する傾向があるため)クラスに過度に依存する必要があるクラスは必要ありませんがA、インターフェイス内で指定されたpromiseに依存する必要がありますA。