251 Stimmen

Unterschied zwischen Vererbung und Komposition

Sind Zusammensetzung und Vererbung dasselbe? Wenn ich das Kompositionsmuster implementieren möchte, wie kann ich das in Java tun?

2 Stimmen

Andere damit zusammenhängende Frage: Gibt es irgendetwas, das durch Komposition nicht erreicht werden kann, was durch Vererbung möglich ist? stackoverflow.com/questions/2238642/

1 Stimmen

2 Stimmen

Dieser Artikel war für mich sehr nützlich und hilfreich: thoughtworks.com/insights/blog/

379voto

polygenelubricants Punkte 362173

Sie sind völlig unterschiedlich. Vererbung ist eine "ist-a" Beziehung. Die Komposition ist eine "hat-a" .

Sie komponieren, indem Sie eine Instanz einer anderen Klasse C als ein Feld Ihrer Klasse, anstatt die C . Ein gutes Beispiel, bei dem Komposition viel besser gewesen wäre als Vererbung, ist java.util.Stack die sich derzeit auf java.util.Vector . Dies wird nun als Fehler angesehen. Ein Stapel "ist-nicht-ein" Vektor; es sollte nicht erlaubt sein, Elemente willkürlich einzufügen und zu entfernen. Stattdessen hätte es Komposition heißen sollen.

Leider ist es zu spät, diesen Entwurfsfehler zu korrigieren, da eine Änderung der Vererbungshierarchie die Kompatibilität mit bestehendem Code zerstören würde. Hatte Stack Komposition anstelle von Vererbung verwendet, kann sie jederzeit geändert werden, um eine andere Datenstruktur zu verwenden, ohne gegen die API .

Ich empfehle das Buch von Josh Bloch Effektives Java 2. Auflage

  • Punkt 16: Komposition vor Vererbung bevorzugen
  • Punkt 17: Vererbung gestalten und dokumentieren oder verbieten

Bei einem guten objektorientierten Design geht es nicht darum, bestehende Klassen großzügig zu erweitern. Ihr erster Instinkt sollte sein, stattdessen zu komponieren.


Siehe auch:

5 Stimmen

Interessant. Warum nicht einfach eine neue Klasse java.util.Stack2 erstellen, die Komposition verwendet?

7 Stimmen

Ich schätze diese Antwort; allerdings habe ich das Gefühl, dass die Antwort vom Thema abweicht und sich mehr mit dem Design der Sprache (und eines bestimmten Pakets) befasst, als dass sie die gestellte Frage bezüglich Komposition vs. Vererbung beantwortet. Ich bin ein großer Fan davon, die Frage auf SO zu beantworten, indem ich Ressourcen zitiere - und nicht auf externe Ressourcen verweise, ohne eine ausführlichere Zusammenfassung als eine einzeilige Zusammenfassung zu liefern.

6 Stimmen

Schlechtes Beispiel: Ich musste extra suchen, um zu verstehen, was Vector und Stack sind.

253voto

codaddict Punkte 426877

Zusammensetzung bedeutet HAS A
Vererbung bedeutet IS A

Example : Auto hat eine Motor und Auto ist eine Auto

In der Programmierung wird dies wie folgt dargestellt:

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.
}

9 Stimmen

Ich würde "Automobil" in "motorisiertes Fahrzeug" ändern, da Autos und Automobile in vielen Zusammenhängen gleichbedeutend sind.

7 Stimmen

@hexafraction Ich stimme zu, dass Fahrzeug wahrscheinlich die bessere Wahl wäre, aber gleichzeitig hat -codaddict- den Punkt für die gestellte Frage sehr gut illustriert.

6 Stimmen

"ein Motor" :-/

58voto

Manoj Kumar Saini Punkte 589

Wie gefährlich kann Vererbung sein?

Nehmen wir ein Beispiel

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

1) Wie im obigen Code deutlich wird, ist die Klasse Y sehr stark mit der Klasse X gekoppelt. Wenn sich in der Superklasse X etwas ändert, kann es in Y zu einem dramatischen Bruch kommen. Angenommen, die Klasse X implementiert in Zukunft eine Methode mit folgender Signatur

public int work(){
}

Die Klasse X wird geändert, aber die Klasse Y wird dadurch nicht mehr kompilierbar. SO kann diese Art von Abhängigkeit bis zu jeder Ebene gehen und sehr gefährlich sein. Jedes Mal, wenn die Oberklasse nicht den vollen Einblick in den Code aller ihrer Unterklassen hat, kann es sein, dass die Unterklasse die ganze Zeit mitbekommt, was in der Oberklasse passiert. Wir müssen also diese starke und unnötige Kopplung vermeiden.

Wie lässt sich dieses Problem durch Komposition lösen?

Sehen wir uns das gleiche Beispiel noch einmal an

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

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

Hier erstellen wir eine Referenz der Klasse X in der Klasse Y und rufen eine Methode der Klasse X auf, indem wir eine Instanz der Klasse X erstellen. Jetzt ist die starke Kopplung aufgehoben. Oberklasse und Unterklasse sind jetzt in hohem Maße unabhängig voneinander. Die Klassen können frei Änderungen vornehmen, die in der Vererbungssituation gefährlich waren.

2) Der zweite sehr gute Vorteil der Komposition besteht darin, dass sie Flexibilität beim Methodenaufruf bietet, zum Beispiel :

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

public class Test{    
    R r;    
}

In der Klasse Test kann ich mit Hilfe von r-Referenzen sowohl Methoden der Klasse X als auch der Klasse Y aufrufen. Diese Flexibilität gab es bei der Vererbung nie.

3) Ein weiterer großer Vorteil: Unit-Tests

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

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

Wenn im obigen Beispiel der Zustand der Instanz x nicht bekannt ist, kann sie leicht mit Hilfe einiger Testdaten nachgebildet werden, und alle Methoden können leicht getestet werden. Dies war bei der Vererbung überhaupt nicht möglich, da man stark von der Oberklasse abhängig war, um den Zustand der Instanz zu ermitteln und eine Methode auszuführen.

4) Ein weiterer guter Grund, warum wir Vererbung vermeiden sollten, ist, dass Java keine Mehrfachvererbung unterstützt.

Nehmen wir ein Beispiel, um dies zu verstehen:

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

Gut zu wissen:

  1. Komposition kann leicht zur Laufzeit erreicht werden, während die Vererbung ihre Funktionen zur Kompilierzeit bereitstellt.

  2. Komposition ist auch als HAS-A-Beziehung und Vererbung als IS-A-Beziehung bekannt

Machen Sie es sich also zur Gewohnheit, aus den oben genannten Gründen immer die Komposition der Vererbung vorzuziehen.

7 Stimmen

Zustimmen, aber angesichts Ihrer Lösung mit Zusammensetzung....wir immer noch tun müssen ein Babysitter zum Beispiel jetzt Superklasse X ändern Sie den Methodennamen von do zu tun....dann Unterklasse Y müssen auch beibehalten werden (muss auch geändert werden) dies ist immer noch enge Kopplung? Und wie werden wir sie wieder los?

1 Stimmen

@stuckedoverflow Das Ändern von Verträgen durch Namen oder Unterschrift ist ein Anti-Muster. Neue Erweiterungen sind jedoch akzeptabel. (O in SOLID)

22voto

Kris Punkte 576

Die von @Michael Rodrigues gegebene Antwort ist nicht korrekt (ich bitte um Entschuldigung; ich bin nicht in der Lage, einen direkten Kommentar abzugeben) und könnte zu einiger Verwirrung führen.

Implementierung der Schnittstelle ist eine Form der Vererbung ... wenn Sie eine Schnittstelle implementieren, erben Sie nicht nur alle Konstanten, sondern Sie verpflichten Ihr Objekt dazu, den von der Schnittstelle spezifizierten Typ zu haben; es ist immer noch ein " ist- " Beziehung. Wenn ein Auto Folgendes implementiert Ausfüllbar das Auto " ist- " Ausfüllbar und kann in Ihrem Code überall dort verwendet werden, wo Sie eine Ausfüllbar .

Die Komposition unterscheidet sich grundlegend von der Vererbung. Wenn Sie Komposition verwenden, machen Sie (wie in den anderen Antworten erwähnt) eine " hat-a "Beziehung zwischen zwei Objekten, im Gegensatz zu der " ist- "Beziehung, die Sie herstellen, wenn Sie die Vererbung verwenden .

Wenn ich also, ausgehend von den Beispielen für Autos in den anderen Fragen, sagen wollte, dass ein Auto " hat-a "Gastank, würde ich die Zusammensetzung wie folgt verwenden:

public class Car {

private GasTank myCarsGasTank;

}

Ich hoffe, damit sind alle Missverständnisse ausgeräumt.

21voto

frictionlesspulley Punkte 9328

Vererbung bringt hervor IS-A Beziehung. Zusammensetzung bringt hervor HAS-A-Beziehung . Strategiemuster erklären, dass Composition in Fällen verwendet werden sollte, in denen es Familien von Algorithmen gibt, die ein bestimmtes Verhalten definieren.
Klassisches Beispiel ist eine Entenklasse, die ein Flugverhalten implementiert.

public interface Flyable{
 public void fly();
}

public class Duck {
 Flyable fly;

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

So können wir mehrere Klassen haben, die das Fliegen implementieren z.B.:

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");
  }
}

Wäre es nach dem Prinzip der Vererbung gegangen, hätten wir zwei verschiedene Klassen von Vögeln, die die Funktion Fliegen immer wieder neu implementieren. Vererbung und Komposition sind also etwas völlig anderes.

0 Stimmen

Was sind die Nachteile der Einführung von Duck BackwardFlying oder BackwardFlyer?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X