「継承よりも好みの構成」についてよく耳にします(そしてこのサイトで読みます)。
しかし、Compositonとは何ですか? Person:Mammal:Animalの観点から継承を理解していますが、Compostionの定義はどこにも実際に見ることができません。
合成とは、単純な型を組み合わせてより複雑な型を作成することです。あなたの例では、構成は次のようになります。
Animal:
Skin animalSkin
Organs animalOrgans
Mammal::Animal:
Hair/fur mammalFur
warm-blooded-based_cirulation_system heartAndStuff
Person::Mammal:
string firstName
string lastName
完全に合成したい(そしてすべての継承を取り除いた)場合は、次のようになります。
Animal:
Skin animalSkin
Organs animalOrgans
Mammal:
private Animal _animalRef
Hair/fur mammalFur
warm-blooded-based_cirulation_system heartAndStuff
Person:
private Mammal _mammalRef
string firstName
string lastName
このアプローチの利点は、タイプMammal
およびPerson
が以前の親のインターフェースに準拠する必要がないことです。このcouldは良いことがあります。スーパークラスへの変更がサブクラスに深刻な影響を与えることがあるためです。これらのクラスのプライベートインスタンスを介してこれらのクラスのプロパティと動作にアクセスできます。これらの以前のスーパークラスの動作を公開する場合は、単純にパブリックメソッドにラップできます。
私はここで良い例との良いリンクを見つけました: http://www.artima.com/designtechniques/compoinh.html
構成は、単に全体を構成する部分です。車には車輪、エンジン、座席があります。継承は「is」関係です。構図は「持っている」関係です。
クラスに動作を与えるには3つの方法があります。その動作をクラスに書き込むことができます。目的の動作を持つクラスから継承できます。または、目的の動作を持つクラスをフィールドまたはメンバー変数としてクラスに組み込むことができます。最後の2つはコードの再利用の形式を表し、最後の2つ(構成)が一般的に推奨されます。実際にクラスに目的の動作を与えるわけではありません-フィールドでメソッドを呼び出す必要がありますが、クラス設計の制約が少なくなり、テストとコードのデバッグが容易になります。継承には場所がありますが、構成を優先する必要があります。
class Engine
{
}
class Automobile
{
}
class Car extends Automobile // car "is a" automobile //inheritance here
{
Engine engine; // car "has a" engine //composition here
}
Composition-オブジェクトの機能は、異なるクラスの集合で構成されています。実際には、これは作業が延期される別のクラスへのポインタを保持することを意味します。
Inheritance-オブジェクトの機能は、その独自の機能とその親クラスの機能で構成されます。
継承よりも合成が優先される理由については、 円楕円問題 をご覧ください。
コンポジションの例は、クラスを継承するのではなく、別のクラス内にクラスのインスタンスがある場合です
This pageには、なぜ人々が「継承よりも好み」と言う理由を説明する良い記事があります。