1984 Stimmen

Bevorzugen Sie Komposition statt Vererbung?

Warum Komposition der Vererbung vorziehen? Welche Kompromisse gibt es für jeden Ansatz? Wann sollten Sie Vererbung der Komposition vorziehen?

6 Stimmen

6 Stimmen

In einem Satz Vererbung ist öffentlich, wenn Sie eine öffentliche Methode haben und Sie ändern es ändert die veröffentlichte api. wenn Sie Zusammensetzung haben und das Objekt komponiert hat sich geändert, müssen Sie nicht Ihre veröffentlichte api ändern.

4voto

Enrique Molinari Punkte 297

Vererbung ist ein sehr leistungsfähiger Mechanismus für die Wiederverwendung von Code. Aber sie muss richtig eingesetzt werden. Ich würde sagen, dass Vererbung richtig eingesetzt wird, wenn die Unterklasse auch ein Untertyp der Oberklasse ist. Wie bereits erwähnt, ist das Liskov-Substitutionsprinzip hier der entscheidende Punkt.

Unterklasse ist nicht dasselbe wie Untertyp. Sie können Unterklassen erstellen, die keine Subtypen sind (und in diesem Fall sollten Sie die Komposition verwenden). Um zu verstehen, was ein Untertyp ist, sollten wir zunächst erklären, was ein Typ ist.

Wenn wir sagen, dass die Zahl 5 vom Typ Integer ist, geben wir damit an, dass 5 zu einer Menge möglicher Werte gehört (siehe als Beispiel die möglichen Werte für die primitiven Java-Typen). Wir sagen auch, dass es eine gültige Menge von Methoden gibt, die ich mit dem Wert durchführen kann, wie Addition und Subtraktion. Und schließlich geben wir an, dass es eine Reihe von Eigenschaften gibt, die immer erfüllt sind, z. B. wenn ich die Werte 3 und 5 addiere, erhalte ich 8 als Ergebnis.

Ein weiteres Beispiel sind die abstrakten Datentypen Set of Integers und List of Integers, deren Werte auf Integer beschränkt sind. Sie unterstützen beide eine Reihe von Methoden, wie add(newValue) und size(). Und beide haben unterschiedliche Eigenschaften (Klasseninvariante), Sets erlaubt keine Duplikate, während List Duplikate zulässt (natürlich gibt es noch andere Eigenschaften, die beide erfüllen).

Ein Subtyp ist ebenfalls ein Typ, der in Beziehung zu einem anderen Typ steht, dem sogenannten übergeordneten Typ (oder Supertyp). Der Untertyp muss die Merkmale (Werte, Methoden und Eigenschaften) des übergeordneten Typs erfüllen. Die Beziehung bedeutet, dass der Supertyp in jedem Kontext, in dem er erwartet wird, durch einen Subtyp ersetzt werden kann, ohne das Verhalten der Ausführung zu beeinflussen. Schauen wir uns nun etwas Code an, um zu verdeutlichen, was ich sage. Angenommen, ich schreibe eine Liste von Ganzzahlen (in einer Art Pseudosprache):

class List {
  data = new Array();

  Integer size() {
    return data.length;
  }

  add(Integer anInteger) {
    data[data.length] = anInteger;
  }
}

Dann schreibe ich die Menge der ganzen Zahlen als Unterklasse der Liste der ganzen Zahlen:

class Set, inheriting from: List {
  add(Integer anInteger) {
     if (data.notContains(anInteger)) {
       super.add(anInteger);
     }
  }
}

Unsere Klasse Set of Integers ist eine Unterklasse von List of Integers, ist aber kein Subtyp, da sie nicht alle Eigenschaften der Klasse List erfüllt. Die Werte und die Signatur der Methoden sind erfüllt, aber die Eigenschaften sind es nicht. Das Verhalten der Methode add(Integer) wurde eindeutig geändert, wobei die Eigenschaften des übergeordneten Typs nicht beibehalten wurden. Stellen Sie sich die Situation aus der Sicht des Clients Ihrer Klassen vor. Er könnte eine Menge von Ganzzahlen erhalten, wo eine Liste von Ganzzahlen erwartet wird. Der Kunde möchte vielleicht einen Wert hinzufügen und diesen Wert zur Liste hinzugefügt bekommen, auch wenn dieser Wert bereits in der Liste vorhanden ist. Aber wenn der Wert bereits vorhanden ist, wird er nicht hinzugefügt. Eine große Überraschung für sie!

Dies ist ein klassisches Beispiel für eine unsachgemäße Verwendung der Vererbung. Verwenden Sie in diesem Fall Komposition.

(ein Fragment aus: Vererbung richtig einsetzen ).

4voto

Parag Punkte 11383

Ich stimme mit @Pavel überein, wenn er sagt, dass es Orte für die Komposition und Orte für die Vererbung gibt.

Wenn Sie eine dieser Fragen bejahen, sollten Sie eine Erbschaft antreten.

  • Ist Ihre Klasse Teil einer Struktur, die von Polymorphismus profitiert? Wenn Sie beispielsweise eine Klasse Shape haben, die eine Methode namens draw() deklariert, dann müssen die Klassen Circle und Square eindeutig Unterklassen von Shape sein, damit ihre Client-Klassen von Shape und nicht von bestimmten Unterklassen abhängen.
  • Muss Ihre Klasse Interaktionen auf hoher Ebene wiederverwenden, die in einer anderen Klasse definiert sind? Die Template-Methode Entwurfsmuster wäre ohne Vererbung nicht umsetzbar. Ich glaube, alle erweiterbaren Frameworks verwenden dieses Muster.

Wenn Sie jedoch ausschließlich die Wiederverwendung von Code beabsichtigen, ist die Komposition wahrscheinlich die bessere Wahl.

3voto

Eine Faustregel, die ich gehört habe, lautet, dass Vererbung verwendet werden sollte, wenn es sich um eine "ist-a"-Beziehung handelt, und Komposition, wenn es sich um eine "hat-a"-Beziehung handelt. Aber selbst dann sollte man sich immer für die Komposition entscheiden, weil dadurch ein Großteil der Komplexität entfällt.

2voto

Shami Qureshi Punkte 69

Zusammensetzung vs. Vererbung ist ein weites Thema. Es gibt keine wirkliche Antwort auf die Frage, was besser ist, denn ich denke, es hängt alles von der Gestaltung des Systems ab.

Im Allgemeinen liefert die Art der Beziehung zwischen den Objekten bessere Informationen, um eines von ihnen auszuwählen.

Wenn der Beziehungstyp "IS-A"-Beziehung ist, dann ist Vererbung der bessere Ansatz. Wenn der Beziehungstyp eine "HAS-A"-Beziehung ist, dann ist Komposition der bessere Ansatz.

Das hängt ganz von der Beziehung zwischen den Unternehmen ab.

2voto

Veverke Punkte 5425

Wie ich sehe, hat noch niemand die Diamantproblem die bei der Vererbung auftreten können.

Wenn die Klassen B und C von A erben und beide die Methode X außer Kraft setzen und eine vierte Klasse D sowohl von B als auch von C erbt und X nicht außer Kraft setzt, welche Implementierung von X soll D dann verwenden?

Wikipedia bietet einen guten Überblick über das Thema, um das es in dieser Frage geht.

1 Stimmen

D erbt B und C, nicht A. Wenn ja, dann würde es die Implementierung von X verwenden, die in Klasse A enthalten ist.

1 Stimmen

@fabricio: Danke, ich habe den Text bearbeitet. Übrigens kann ein solches Szenario nicht in Sprachen auftreten, die keine Mehrfachvererbung von Klassen zulassen, habe ich Recht?

0 Stimmen

Ja, Sie haben Recht und ich habe noch nie mit einem gearbeitet, das Mehrfachvererbung erlaubt (wie im Beispiel des Diamantproblems)

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