私は「継承よりも好ましい構成」について多くのことを聞いています(そしてこのサイトで読んでいます)。
しかし、Compositonとは何ですか?人:哺乳類:動物の観点から相続は理解できますが、構成の定義はどこにもわかりません。誰かが私に記入してもらえますか?
私は「継承よりも好ましい構成」について多くのことを聞いています(そしてこのサイトで読んでいます)。
しかし、Compositonとは何ですか?人:哺乳類:動物の観点から相続は理解できますが、構成の定義はどこにもわかりません。誰かが私に記入してもらえますか?
構成とは、単純なタイプを組み合わせてより複雑なタイプを作成することを指します。あなたの例では、構成は次のようになります。
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
が前の親のインターフェースに準拠する必要がないことです。スーパークラスへの変更がサブクラスに深刻な影響を与えることがあるため、これは良いことかもしれません。これらのクラスのプライベートインスタンスを介して、これらのクラスのプロパティと動作にアクセスできます。これらの以前のスーパークラスの動作を公開する場合は、パブリックメソッドでラップするだけです。
ここで良い例との良いリンクを見つけました:http ://www.artima.com/designtechniques/compoinh.html
構成は、単に全体を構成する部分です。車には車輪、エンジン、座席があります。継承は「は」の関係です。作曲は「持っている」関係です。
クラスに動作を与える方法は3つあります。その振る舞いをクラスに書き込むことができます。目的の動作を持つクラスから継承できます。または、目的の動作をするクラスをフィールドまたはメンバー変数としてクラスに組み込むことができます。最後の2つはコードの再利用の形式を表しており、最後の1つである構成が一般的に好まれます。実際にはクラスに望ましい動作を与えるわけではありませんが、フィールドでメソッドを呼び出す必要がありますが、クラスの設計にかかる制約が少なくなり、コードのテストとデバッグが容易になります。継承にはその場所がありますが、構成を優先する必要があります。
class Engine
{
}
class Automobile
{
}
class Car extends Automobile // car "is a" automobile //inheritance here
{
Engine engine; // car "has a" engine //composition here
}
構成-オブジェクトの機能は、さまざまなクラスの集合体で構成されています。実際には、これは、作業が延期される別のクラスへのポインターを保持することを意味します。
継承-オブジェクトの機能は、それ自体の機能とその親クラスの機能で構成されます。
継承よりも合成が優先される理由については、円-楕円問題を見てください。
コンポジションの例は、クラスから継承するのではなく、別のクラス内にクラスのインスタンスがある場合です。
このページには、人々が「継承よりもコンポジションを好む」と言う理由を説明する良い記事があり、その理由の例がいくつかあります。
構成
単に、他のオブジェクトへの参照であるインスタンス変数を使用することを意味します。
1-継承によるコード
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple extends Fruit {
}
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
を実行するとExample1 application
、「ピーリングは魅力的です。」と出力されます。これは、AppleがFruitのの実装を継承(再利用)しているためですpeel()
。ただし、将来のある時点で、の戻り値をpeel()
Peel型に変更したい場合は、のコードを壊しますExample1
。Example1がAppleを直接使用し、Fruitについて明示的に言及していなくても、Fruitへの変更はExample1のコードを壊します。詳細については、以下を参照してください。
class Peel {
private int peelCount;
public Peel(int peelCount) {
this.peelCount = peelCount;
}
public int getPeelCount() {
return peelCount;
}
//...
}
class Fruit {
// Return a Peel object that
// results from the peeling activity.
public Peel peel() {
System.out.println("Peeling is appealing.");
return new Peel(1);
}
}
// Apple still compiles and works fine
class Apple extends Fruit {
}
// This old implementation of Example1
// is broken and won't compile.
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
2-コンポジションを介したコードコンポジションは、の実装Apple
を再利用する
ための代替方法を提供します。を拡張する代わりに、インスタンスへの参照を保持し、Fruitを呼び出すだけの独自のメソッドを定義できます。コードは次のとおりです。Fruit's
peel()
Fruit
Apple
Fruit
peel()
peel()
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
return fruit.peel();
}
}
class Example2 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
詳細については、 refを参照してください