web-dev-qa-db-ja.com

継承と構成の違い

構成と継承は同じですか?構成パターンを実装する場合、Javaでどのように実行できますか?

179
gmhk

それらはまったく異なります。継承は "is-a"関係です。構成はa "has-a"です。

Cを拡張する代わりに、別のクラスCのインスタンスをクラスのフィールドとして持つことにより、構成を行います。構成が継承よりもはるかに優れていた良い例はJava.util.Stackで、これは現在Java.util.Vectorを拡張しています。これは現在、失策と見なされています。スタック "is-NOT-a"ベクトル。要素を任意に挿入したり削除したりすることはできません。代わりに作曲すべきでした。

残念ながら、継承階層を変更すると既存のコードとの互換性が失われるため、この設計上の間違いを修正するには遅すぎます。 Stackは継承の代わりに構成を使用していましたが、APIに違反することなく別のデータ構造を使用するようにいつでも変更できます

Josh Blochの本を強くお勧めしますEffective Java 2nd Edition

  • 項目16:継承よりも有利な構成
  • 項目17:継承のための設計と文書化、または禁止

優れたオブジェクト指向設計とは、既存のクラスを自由に拡張することではありません。最初の本能は、代わりに作曲することです。


こちらもご覧ください:

276

構成はHAS Aを意味します
継承とはIS Aを意味します

Example:Car has Engine and Car is a Automobile

プログラミングでは、これは次のように表されます。

class Engine {} // The Engine class.

class Automobile {} // Automobile class which is parent to Car class.

class Car extends Automobile { // Car is an Automobile, so Car class extends Automobile class.
  private Engine engine; // Car has an Engine so, Car class has an instance of Engine class as its member.
}
184
codaddict

継承はどのように危険なのでしょうか?

例を見てみましょう

public class X{    
   public void do(){    
   }    
}    
Public Class Y extends X{
   public void work(){    
       do();    
   }
}

1)上記のコードで明らかなように、クラスYはクラスXと非常に強い結合を持っています。スーパークラスXで何か変更があった場合、Yは劇的に壊れる可能性があります。将来、クラスXが以下の署名で動作するメソッドを実装するとします

public int work(){
}

変更はクラスXで行われますが、クラスYはコンパイルできなくなります。 SOこの種類の依存関係はどのレベルにも達する可能性があり、非常に危険です。スーパークラスは、そのすべてのサブクラス内のコードに対して完全な可視性を持たない場合があり、サブクラスは常にスーパークラスで何が起こっているかを常に認識している場合があります。したがって、この強力で不必要な結合を避ける必要があります。

コンポジションはこの問題をどのように解決しますか?

同じ例を修正して見てみましょう

public class X{
    public void do(){
    }
}

Public Class Y{
    X x = new X();    
    public void work(){    
        x.do();
    }
}

ここでは、YクラスでXクラスの参照を作成し、Xクラスのインスタンスを作成してXクラスのメソッドを呼び出しています。これで、強力なカップリングはすべてなくなりました。現在、スーパークラスとサブクラスは互いに非常に独立しています。クラスは、継承の状況で危険な変更を自由に行うことができます。

2)合成の2番目の非常に良い利点は、メソッド呼び出しの柔軟性を提供することです。たとえば、

class X implements R
{}
class Y implements R
{}

public class Test{    
    R r;    
}

R参照を使用したテストクラスでは、XクラスとYクラスのメソッドを呼び出すことができます。この柔軟性は継承には決してありませんでした

3)もう1つの大きな利点:単体テスト

public class X {
    public void do(){
    }
}

Public Class Y {
    X x = new X();    
    public void work(){    
        x.do();    
    }    
}

上記の例では、xインスタンスの状態が不明な場合、いくつかのテストデータを使用して簡単にモックアップでき、すべてのメソッドを簡単にテストできます。インスタンスの状態を取得してメソッドを実行するためにスーパークラスに大きく依存していたため、これは継承ではまったく不可能でした。

4)継承を避けるべきもう1つの理由は、Javaが多重継承をサポートしていないことです。

これを理解するために例を挙げましょう:

Public class Transaction {
    Banking b;
    public static void main(String a[])    
    {    
        b = new Deposit();    
        if(b.deposit()){    
            b = new Credit();
            c.credit();    
        }
    }
}

知っておきたいこと:

  1. 構成は実行時に簡単に実現され、継承はコンパイル時に機能を提供します

  2. 構成はHAS-A関係とも呼ばれ、継承はIS-A関係とも呼ばれます

したがって、上記のさまざまな理由から、常に継承よりも合成を好む習慣にしてください。

32

@Michael Rodriguesの回答は正しくなく(謝罪。直接コメントすることはできません)、混乱を招く可能性があります。

インターフェイスの実装 継承の形式です ...インターフェイスを実装すると、すべての定数を継承するだけでなく、オブジェクトをインターフェイスで指定された型にコミットします。まだ「is-a」の関係です。車がFillableを実装している場合、車は "is-a" Fillableであり、 Fillableを使用するあらゆる場所でコードで使用されます。

構成は、継承とは根本的に異なります。 コンポジションを使用すると、(他の回答のメモとして)2つのオブジェクト間で「has-a」関係を作成します。継承を使用するときに作成する「is-a」の関係

したがって、他の質問の自動車の例から、自動車「has-a」ガソリンタンクと言いたい場合は、構図を使用します。次のように:

public class Car {

private GasTank myCarsGasTank;

}

うまくいけば、誤解を解消できます。

19
Kris

継承を引き出すIS-A関係。 構成を引き出すHAS-A関係。戦略パターンは、特定の動作を定義するアルゴリズムのファミリーがある場合に構成を使用する必要があることを説明します。
飛行動作を実装するアヒルクラスの典型的な例。

public interface Flyable{
 public void fly();
}

public class Duck {
 Flyable fly;

 public Duck(){
  fly = new BackwardFlying();
 }
}

したがって、たとえば、飛行を実装する複数のクラスを持つことができます。

public class BackwardFlying implements Flyable{
  public void fly(){
    Systemout.println("Flies backward ");
  }
}
public class FastFlying implements Flyable{
  public void fly(){
    Systemout.println("Flies 100 miles/sec");
  }
}

もし継承のためなら、fly関数を何度も実装する2つの異なるクラスの鳥がいるでしょう。したがって、継承と構成は完全に異なります。

14

構図はその通りです-部品を差し込んでオブジェクトを作成します。

EDITこの回答の残りは、誤って次の前提に基づいています。
これはインターフェイスで実現されます。
たとえば、上記のCarname__の例を使用すると、

Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel

したがって、いくつかの標準的な理論上のコンポーネントを使用して、オブジェクトを構築できます。 Housename__がその居住者を保護する方法、およびCarname__がその居住者を保護する方法を記入するのはあなたの仕事です。

継承は、他の方法と同様です。完全な(または半完全な)オブジェクトから始めて、変更するさまざまなビットを置換またはオーバーライドします。

たとえば、MotorVehiclename__にはFuelablename__メソッドとDrivename__メソッドが付属する場合があります。 Fuelメソッドはバイクと車を埋めるのと同じであるためそのままにしておきますが、MotorbikeはDrivename__とはまったく異なる方法で駆動するため、Carname__メソッドをオーバーライドできます。

継承により、一部のクラスはすでに完全に実装されていますが、他のクラスにはオーバーライドを強制されるメソッドがあります。コンポジションでは、何も与えられません。 (ただし、何か他のクラスが存在する場合は、他のクラスのメソッドを呼び出してインターフェイスを実装できます)。

IUsesFuelなどのメソッドがある場合、それが車であるかどうかに関係なく、燃料を供給できるオブジェクトを扱うことだけを心配する他の場所(別のクラス、別のプロジェクト)にメソッドを持つことができるため、構成はより柔軟であると見なされますボート、ストーブ、バーベキューなど。インターフェースは、そのインターフェースを実装するというクラスが、実際にそのインターフェースがすべてについているメソッドを持つことを義務付けています。例えば、

iFuelable Interface:
   void AddSomeFuel()
   void UseSomeFuel()
   int  percentageFull()

その後、あなたはどこか他の方法を持つことができます

private void FillHerUp(iFuelable : objectToFill) {

   Do while (objectToFill.percentageFull() <= 100)  {

        objectToFill.AddSomeFuel();
   }

奇妙な例ですが、オブジェクトがiUsesFuelname__を実装しているため、このメソッドが何を埋めているかを気にしないことを示しています。物語の終わり。

代わりにInheritanceを使用した場合は、FillHerUpname__およびMotorVehiclesname__を処理するために、異なるBarbecuesname__メソッドが必要になります(ただし、継承元となる奇妙な "ObjectThatUsesFuel"ベースオブジェクトがない限り)。

7

構成と継承は同じですか?

それらは同じではありません。

構成 :オブジェクトのグループをオブジェクトの単一インスタンスと同じ方法で処理する必要があります。コンポジットの目的は、オブジェクトをツリー構造に「構成」して、部分全体の階層を表す

継承 :クラスは、直接または間接に関係なく、すべてのスーパークラスからフィールドとメソッドを継承します。サブクラスは、継承するメソッドをオーバーライドするか、継承するフィールドまたはメソッドを非表示にすることができます。

構成パターンを実装する場合、Javaでどのように実行できますか?

Wikipedia 記事は、Javaで複合パターンを実装するのに十分です。

enter image description here

主要参加者:

コンポーネント

  1. 複合コンポーネントを含むすべてのコンポーネントの抽象化です
  2. composition内のオブジェクトのインターフェースを宣言します

  1. 構成のリーフオブジェクトを表します
  2. すべてのComponentメソッドを実装します

コンポジット

  1. 複合コンポーネント(子を持つコンポーネント)を表します
  2. 子を操作するメソッドを実装します
  3. 一般にそれらを子に委任することにより、すべてのコンポーネントメソッドを実装します。

理解するためのコード例Compositeパターン:

import Java.util.List;
import Java.util.ArrayList;

interface Part{
    public double getPrice();
    public String getName();
}
class Engine implements Part{
    String name;
    double price;
    public Engine(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Trunk implements Part{
    String name;
    double price;
    public Trunk(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Body implements Part{
    String name;
    double price;
    public Body(String name,double price){
        this.name = name;
        this.price = price;
    }
    public double getPrice(){
        return price;
    }
    public String getName(){
        return name;
    }
}
class Car implements Part{
    List<Part> parts;
    String name;

    public Car(String name){
        this.name = name;
        parts = new ArrayList<Part>();
    }
    public void addPart(Part part){
        parts.add(part);
    }
    public String getName(){
        return name;
    }
    public String getPartNames(){
        StringBuilder sb = new StringBuilder();
        for ( Part part: parts){
            sb.append(part.getName()).append(" ");
        }
        return sb.toString();
    }
    public double getPrice(){
        double price = 0;
        for ( Part part: parts){
            price += part.getPrice();
        }
        return price;
    }   
}

public class CompositeDemo{
    public static void main(String args[]){
        Part engine = new Engine("DiselEngine",15000);
        Part trunk = new Trunk("Trunk",10000);
        Part body = new Body("Body",12000);

        Car car = new Car("Innova");
        car.addPart(engine);
        car.addPart(trunk);
        car.addPart(body);

        double price = car.getPrice();

        System.out.println("Car name:"+car.getName());
        System.out.println("Car parts:"+car.getPartNames());
        System.out.println("Car price:"+car.getPrice());
    }

}

出力:

Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0

説明:

  1. Partは葉です
  2. Carには多くのパーツが含まれています
  3. 異なるPartsがCarに追加されました
  4. Car=(各価格の合計)の価格パート

構成と継承の長所と短所については、以下の質問を参照してください。

継承よりも合成を優先しますか?

6
Ravindra babu

単純な単語の集約では、関係があることを意味します..

構成は集計の特殊なケースです。より具体的な方法では、制限された集約は合成と呼ばれます。オブジェクトに他のオブジェクトが含まれている場合、含まれるオブジェクトがコンテナオブジェクトの存在なしでは存在できない場合、それはコンポジションと呼ばれます。 例:クラスには生徒が含まれています。クラスなしでは生徒は存在できません。クラスと生徒の間に構成が存在します。

集計を使用する理由

コードの再利用性

集計を使用する場合

コードの再利用は、リレーションシップが存在しない場合の集約によっても最適に達成されます

継承

継承は親子関係である継承手段はRelationShipである

Javaの継承は、1つのオブジェクトが親オブジェクトのすべてのプロパティと動作を取得するメカニズムです。

Java 1 Code Reusabilityでの継承の使用。 2子クラスおよびメソッドオーバーライドに追加機能を追加します(したがって、ランタイムポリモーフィズムを実現できます)。

4
Keshav Gera

別の例として、車のクラスを考えてみましょう。これは構成の適切な使用であり、車はエンジン、トランスミッション、タイヤ、シートなどを「持っている」でしょう。これらのクラスは拡張されません。

4
BlackICE

構成は、何かが個別の部分で構成され、それらの部分と強い関係がある場所です。主要部分が死ぬと、他の部分も死ぬと、彼らは自分の人生を持つことができません。大まかな例は、人体です。心を取り出して、他のすべての部分が死ぬ。

継承とは、既に存在するものを取得して使用することです。強い関係はありません。人は父親の財産を相続することができますが、それなしでもできます。

Javaがわからないため、例を提供できませんが、概念の説明は提供できます。

3
Robert Rocha

2つのクラス間の継承。1つのクラスが別のクラスを拡張し、「IS A」関係を確立します。

もう一方の端のCompositionには、クラス内の別のクラスのインスタンスが含まれ、「Has A関係。 Compositionin Javaは、技術的に多重継承を容易にするので便利です。

3
John Wilson

この例は、継承compositionの違いを明確に説明していると思います。

この例では、継承と構成を使用して問題を解決します。著者は以下の事実に注意を払います; inheritanceでは、スーパークラスの変更により、それを継承する派生クラスで問題が発生する場合があります。

また、継承または構成にUMLを使用すると、表現の違いを確認できます。

http://www.javaworld.com/article/2076814/core-Java/inheritance-versus-composition--which-one-should-you-choose-.html

1
aunte

継承と構成

継承と構成は両方とも、クラスの動作の再利用と拡張に使用されます。

IS-A関係タイプなどのファミリーアルゴリズムプログラミングモデルで主に使用される継承は、同様の種類のオブジェクトを意味します。例。

  1. ダスターは車です
  2. サファリは車です

これらは車のファミリーに属します。

構成はHAS-A関係のタイプを表します。ダスターには5つのギア、サファリには4つのギアなどのオブジェクトの能力が表示されます。既存のクラスの能力を拡張する必要があるときはいつでも構成を使用します。ダスターオブジェクトにもう1つのギアを追加する必要があります。次に、もう1つのギアオブジェクトを作成し、ダスターオブジェクトに構成する必要があります。

すべての派生クラスがこれらの機能を必要とするまで/しない限り、基本クラスの変更を行わないでください。このシナリオでは、Composition.Suchを使用する必要があります。

クラスBから派生したクラスA

クラスCから派生したクラスA

クラスAから派生したクラスA.

クラスAに機能を追加すると、クラスCとDがそれらの機能を必要としない場合でも、すべてのサブクラスで使用できます。このシナリオでは、これらの機能用に別のクラスを作成し、必要なクラスに構成する必要があります(これがクラスB)です。

以下に例を示します:

          // This is a base class
                 public abstract class Car
                    {
                       //Define prototype
                       public abstract void color();
                       public void Gear() {
                           Console.WriteLine("Car has a four Gear");
                       }
                    }


           // Here is the use of inheritence
           // This Desire class have four gears.
          //  But we need to add one more gear that is Neutral gear.

          public class Desire : Car
                   {
                       Neutral obj = null;
                       public Desire()
                       {
     // Here we are incorporating neutral gear(It is the use of composition). 
     // Now this class would have five gear. 

                           obj = new Neutral();
                           obj.NeutralGear();
                       }

                       public override void color()
                       {
                           Console.WriteLine("This is a white color car");
                       }

                   }


             // This Safari class have four gears and it is not required the neutral
             //  gear and hence we don't need to compose here.

                   public class Safari :Car{
                       public Safari()
                       { }

                       public override void color()
                       {
                           Console.WriteLine("This is a red color car");
                       }


                   }

   // This class represents the neutral gear and it would be used as a composition.

   public class Neutral {
                      public void NeutralGear() {
                           Console.WriteLine("This is a Neutral Gear");
                       }
                   }
1

継承とコンポジションの両方がコードの再利用性を提供しますが、Javaのコンポジションと継承の主な違いは、コンポジションはコードを拡張せずに再利用できることですが、継承の場合、コードまたは機能の再利用のためにクラスを拡張する必要があります。この事実から生じるもう1つの違いは、Compositionを使用することで、拡張可能ではないが、継承がそのような場合にコードを再利用できない最終クラスでもコードを再利用できることです。また、コンポジションを使用することで、メンバー変数として宣言されている多くのクラスのコードを再利用できますが、継承を使用すると、Javaでは1つのクラスしか拡張できないため、1つのクラスだけでコードを再利用できます継承はJavaではサポートされていません。ただし、1つのクラスが複数のクラスを拡張できるため、C++でこれを行うことができます。ところで、あなたはいつも javaの継承よりも合成を好む、それは私だけでなく、Joshua Blochも彼の本で示唆しています

1
Nitin Pawar

継承とは、クラスの完全な機能を再利用することを意味します。ここで、私のクラスはスーパークラスのすべてのメソッドを使用する必要があり、継承の場合、クラスはスーパークラスと密結合され、コードは両方のクラスで複製されます。

しかし、作曲を使用して別のクラスと話すと、これらすべての問題を克服できます。構成は、別のクラスの属性を、話したいクラスに宣言しています。そして、そのクラスを使用して、その属性を使用してどのような機能を取得できるかを確認します。

0
Vikas Kapadiya

構成とは、特定のクラスと関係があるクラスにオブジェクトを作成することを意味します。学生がアカウントと関係があると仮定します。

継承とは、これは拡張機能を備えた以前のクラスです。つまり、この新しいクラスは、拡張機能を備えた古いクラスです。学生は学生ですが、すべての学生は人間であるとします。だから、学生と人間との関係があります。これは継承です。

0
HM Nayem

いいえ、両方とも異なります。構成は「HAS-A」関係に従い、継承は「IS-A」関係に従います。構成の最良の例は、戦略的パターンでした。

0
Ranga Reddy

構成

  • simpleオブジェクトまたはデータ型を複数のcomplexに結合する方法です
  • 1つのクラスのフィールドが別のクラスで構成されている場合、2つのクラス間に構成関係が存在します
  • has-a関係として呼び出されます

継承

  • 表面的には、継承はコードです再利用
  • すでに管理可能な方法で記述されたコードを拡張できます。
  • 継承はさらに多く、言語レベルで多態性をサポートします!
  • 情報は階層順に管理可能になります
  • 継承を使用すると、既存のクラスからビルディングブロックとして新しいクラスを派生できます。
  • 新しいクラスは、既存のクラスからプロパティとメソッドを継承します
  • ExtendsおよびImplementsキーワードを使用
  • クラス階層があります(直接/間接/単一/複数)
0