59

継承よりも構成を優先する

は非常に人気のあるフレーズです。私はいくつかの記事を読み、最後に各記事は言う

クラス間に純粋な IS-A 関係がある場合は、継承を使用します。

この記事の例:

ここで、AppleFruitの間には明確な IS-A 関係、つまり Apple IS-A Fruit がありますが、継承で実装した場合の落とし穴を示すために、著者はそれを Apple HAS-A Fruit (構成) としても示しました。

ここで、ステートメントの意味が何であるかについて少し混乱しました

クラス間に純粋な IS-A 関係がある場合は、継承を使用します。

継承よりも構成を使用するということは、純粋な IS-A 関係がある場合でも常に構成を適用 しようとし、構成が意味をなさない場合にのみ継承を残すことを意味しますか?

4

7 に答える 7

90

メソッドをオーバーライドして別のポリモーフィックな動作を定義するのではなく、継承を使用してスーパークラスのコードを再利用する場合、多くの場合、継承の代わりに構成を使用する必要があります。

java.util.Propertiesクラスは継承の悪い使い方の良い例です。プロパティを格納するために Hashtable を使用するのではなく、Hashtable を拡張して、そのメソッドを再利用し、委譲を使用してそれらの一部を再実装することを回避します。

于 2012-07-05T12:25:21.197 に答える
7

これは、オブジェクト指向設計で最も議論されているポイントの 1 つだと思います。この記事で示唆されているように、構成は常に継承よりも優先されます。これは、継承を決して使用してはならないという意味ではありません。それがより理にかなっているところにすべきです(議論の余地があります)。

コンポジションを使用することには多くの利点があります。そのうちのいくつかは次のとおりです。

  • 実装を完全に制御できます。つまり、公開しようとしているメソッドのみを公開できます。
  • スーパークラスでの変更は、自分のクラスでのみ変更することで保護できます。クラスを使用するクライアント クラスは、変更する必要はありません。
  • スーパークラスをいつロードするかを制御できます (遅延ロード)
于 2012-07-05T12:26:21.097 に答える
4

良いガイドラインは次のようになると思います。

IS-A 関係がある場合は、継承を使用します。それ以外の場合は、コンポジションを使用します。

この理由は、オブジェクト指向設計の別の概念であるポリモーフィズムに関連しています。ポリモーフィズムは、最初のクラスが 2 番目のクラスのサブクラスであるという条件で、オブジェクトを別のオブジェクトの代わりに使用できる多くの OOP 言語の機能です。

説明のために、ある種類の動物を受け取る関数があると想像してください。継承を使用する場合、機能は 1 つだけです。

void feed( Animal a );

ポリモーフィズムは、入れた動物のサブクラスが受け入れられることを保証します。そうしないと、タイプごとに 1 つの関数を作成する必要があります。これの利点は欠点を上回ると思います (例: カプセル化の減少)。

IS-A 関係がなければ、ポリモーフィズムはあまり効果的ではないと思います。したがって、コンポジションを使用し、クラス間のカプセル化/分離を強化することをお勧めします。

于 2012-07-06T13:57:00.420 に答える
3

記事には、そのようなフレーズはありません。

use inheritance when there is pure IS-A relationship between classes

さらに、Google はあなたの投稿以外の場所では見つけられませんでした。

代わりに、記事には次のように書かれています。

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-それぞれが独自の役割に適しています.

于 2012-07-05T12:31:38.217 に答える
3

また、 Decorator パターンは、継承よりも構成を使用し、オブジェクトに責任を動的に追加できる例であることを付け加えたいと思います。Decorator パターンの例は、Effective Java の「継承よりも構成を優先する」の項目に記載されています。Java API から例を挙げます。BufferedReader は (FileReader、PipedReader、FilterReader などを拡張する代わりに) Reader を装飾するため、あらゆる種類の Reader を装飾する機能を備えています。バッファリング機能は、Decorator パターンである実行時にこれらのリーダーにアタッチされます。

ここで、サブクラス化による拡張は実用的ではありません。

于 2012-07-05T13:20:45.797 に答える
2

関係が永続的な場合は継承を使用します。自由な動作を得るためだけに拡張機能を使用しないでください。これは、IS-A の例で彼らが言及しているものです。拡張クラスが本当に親の拡張である場合にのみ拡張します。カットアンドドライではない場合もありますが、概ねです。コンポジションは、「適切な」クラスから拡張する必要がある場合でも、将来的に柔軟性を提供します。

これは拡張に関する古い記事ですが、素晴らしい記事です。

http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html

于 2012-07-05T12:29:48.953 に答える
0

私はノーと言うでしょう。フルーツ/アップルのシナリオでは、継承を使用するのが理にかなっています。記事の著者も次のように確認しています。「上記の例では、AppleはおそらくFruitであるため、継承を使用する傾向があります」。

サブクラスが明らかにスーパークラスである場合、継承は問題ありません。ただし、実際には、コンポジションを使用してより適切に解決できる状況がさらに多く見つかります。

于 2012-07-05T12:19:29.843 に答える