この質問にはすでに答えがあります。
相続よりも有利な構成
とても人気のあるフレーズです。私はいくつかの記事を読み、最後に各記事は言う
クラス間に純粋なIS-A関係がある場合は、継承を使用してください。
からの例この記事:
ここから林檎そしてフルーツ明確なIS-A関係、すなわちApple IS-A Fruitがありますが、それでも継承して実装した場合の落とし穴を示すためにApple HAS-A Fruit(作曲)として示しています。
私はここで声明の意味は何ですかということで多少混乱しました
クラス間に純粋なIS-A関係がある場合は、継承を使用してください。
継承よりもコンポジションを使うということは、常にやってみるコンポジションを適用するたとえ純粋なIS-A関係があり、継承を残す構図が意味をなさない場合のみ?
メソッドをオーバーライドして別の多態性の振る舞いを定義するのではなく、継承を使用してスーパークラスのコードを再利用する場合、多くの場合、継承の代わりに合成を使用する必要があります。
のjava.util.Properties
classは継承の悪用の良い例です。のではなく使うそのプロパティを格納するためのハッシュテーブル伸びるそのメソッドを再利用し、それらのうちのいくつかを委譲を使って再実装することを避けるためのハッシュテーブル。
java.util.Properties
伸びるHashTable
その結果、デザインに悪影響を及ぼしています。私はLiskov Substitution Principleについて考えましたが、問題ではないと思います。理論的には、パフォーマンス(メモリ)の観点から格納(ハッシュ)メカニズムを変更できると便利かもしれませんが、継承では不可能であり、合成でも可能です。 - FuhrmanatorProperties
伸びるHashtable
継承の悪用の良い例を挙げようProperties
全体を気にしないでくださいHashtable
固有のロジックで、そのサブセットのみが必要なので拡張しないでください。Hashtable
なぜならです一つではない、それだけ用途1 ? - SantiBailors
これは、オブジェクト指向設計で最も議論されている点の1つです。この記事で示唆されているように、コンポジションは継承よりも常に優先されます。それはあなたが継承を使用してはいけないという意味ではありません。あなたはそれがより理にかなっているところ(それは議論の余地があるかもしれません)にあるべきです。
コンポジションを使用することには多くの利点があります。
この記事には、そのようなフレーズはありません。
use inheritance when there is pure IS-A relationship between classes
さらに、グーグルはあなたの投稿以外にそれを見つけられませんでした。
代わりに、記事は読みます:
Make sure inheritance models the is-a relationship.
My main guiding philosophy is that inheritance should be used only when a subclass is-a superclass. In the example above, an Apple likely is-a Fruit, so I would be inclined to use inheritance.
つまり、IS_A関係がある場合は、コンポジションではなく継承を最初に使用してください。そしての好みはありませんusing composition over inheritance
- それぞれが自分の役割に適しています。
each is good for its own role.
+1。これは「私たちの動機」にかかっていると思います。私達は私達のクラス間の関係を確立しています。 「オンリー」の場合コードの再利用Favor composition over inheritance
有効であり、その動機が「実際の関係」をモデル化することである場合。実際にはクラス間に存在するため、継承と合成の両方が独自の役割を果たします。 「にもかかわらず」純粋なIS-A関係がある場合は、継承を選択できます。継承は強い結合のように合成よりも多くの問題を抱えているという事実が、そうでなければ合成を選びます。私は正しいですか? - a Learner
また、それを追加したいと思いますデコレータパターン継承に対する合成を使用し、オブジェクトに責任を動的に追加できる例です。 Decoratorパターンの例は、Effective Javaの項目「継承に優先する構成」で説明されています。 Java APIから例を取ります。 BufferedReaderは(FileReader、PipedReader、FilterReaderなどを拡張するのではなく)Readerを装飾するため、あらゆる種類のReaderを装飾することができます。実行時にこれらのリーダーにバッファリング機能が追加されます。これがDecoratorパターンです。
ここでは、サブクラス化による拡張は実用的ではありません。
私は良いガイドラインがあると思います:
IS-A関係がある場合は、継承を使用してください。それ以外の場合は 組成。
その理由は、オブジェクト指向設計におけるもう1つの概念 - 多態性 - に関連しています。多態性は、最初のクラスが2番目のクラスのサブクラスであるという条件で、あるオブジェクトを別のオブジェクトの代わりに使用できる多くのOOP言語の機能です。
例証するために、あなたが動物のタイプを取り込む機能を持っているかどうか想像してください。継承を使うときは、関数は1つだけです。
void feed( Animal a );
多型性は私たちが入れた動物のどんなサブクラスでも受け入れられることを私たちに保証します。そうでなければ、それぞれの型に対して一つの関数を書くことを強いられるでしょう。私はこれの利点がその欠点(例:カプセル化の減少)を上回ると思います。
IS-A関係がなければ、多態性はそれほど効果的ではないと思います。したがって、合成を使用し、クラス間のカプセル化/分離を強化することをお勧めします。
If there is no IS-A relationship, I think polymorphism won't be very effective. It would thus be better to use composition and have enhanced encapsulation/isolation between classes.
+1 - a Learner
関係が永続的な場合は継承を使用してください。自由な振る舞いをするためだけにextensionを使わないでください。これは彼らがIS-Aの例で言及しているものです。拡張クラスが本当に親の拡張である場合にのみ拡張します。それが切られて乾いていない時があるでしょう、しかし一般に。あなたが「正しい」クラスから拡張する必要があるならば、構成も将来の柔軟性を提供します。
これは古くからの素晴らしい拡張記事です。
http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html
私はノーと言うでしょう。フルーツ/アップルのシナリオでは、継承を使用するのが理にかなっています。記事の執筆者は、「上の例では、Appleは実はFruitである可能性が高いので、継承を使用する傾向がある」とも述べています。
サブクラスが明らかにスーパークラスであれば、継承は問題ありません。しかし実際には、コンポジションを使用して解決した状況がもっとたくさんあります。
<what-your-subclass-models>
明らかにIS-A<what-your-superclass-models>
" - Joffrey