Wie kann ich den Nutzen der Vererbung erklären? [geschlossen]


16

Wenn Sie versuchen, das Konzept der Vererbung in OOP zu erklären, ist das häufigste Beispiel das Beispiel von Säugetieren. IMHO, das ist wirklich ein schlechtes Beispiel, weil es die Neulinge dazu bringt, dieses Konzept falsch zu verwenden. Darüber hinaus ist es kein gewöhnliches Design, mit dem sie in ihrer täglichen Designarbeit konfrontiert werden.

Also, was wird ein schönes, einfaches und konkretes Problem sein, das mit Inheritance gelöst wird?


1
"Das gängige Beispiel sind oft die Säugetiere"? Was meinen Sie? Können Sie einen Link, eine Referenz oder ein Zitat dafür bereitstellen?
S.Lott


3
Was wäre das beste reale Beispiel, um den Nutzen von Inheritance = Bill Gates 'Treuhandfonds für Kinder zu erklären?
Martin Beckett

1
@ Chris: Wie ist diese Frage nicht konstruktiv? Erklären Sie, dass ein Fragesteller und 14 Antwortende alle Zeit verschwenden?
Dan Dascalescu

@DanDascalescu - es wurde vor zwei Jahren geschlossen, als Antwort auf die Meldung "Bitte betrachten Sie das Schließen als nicht konstruktiv: Nach Antworten zu urteilen, die sich darauf häufen, sieht dies aus wie eine typische Listen- / Umfrage-Frage". Wenn Sie der Meinung sind, dass dies falsch ist, bearbeiten Sie es, um zu verdeutlichen, dass dies nicht der Fall ist, und lassen Sie die Community über die Warteschlange zum erneuten Öffnen der Überprüfung entscheiden.
ChrisF

Antworten:


15

An einem rein akademischen Beispiel wie Säugetieren ist nichts auszusetzen. Ich mag auch das Rechteck / Quadrat-Beispiel, weil es darauf hinweist, warum Taxonomien aus der realen Welt nicht immer direkt in die zu erwartende Vererbungsbeziehung übersetzt werden.

Meiner Meinung nach ist das kanonischste Beispiel für jeden Tag ein GUI-Toolkit. Es ist etwas, das jeder benutzt hat, aber Anfänger haben vielleicht nicht begründet, wie sie unter der Haube arbeiten. Sie können darüber sprechen, welche Verhaltensweisen allen Containern, Widgets, Ereignissen usw. gemeinsam sind, ohne detaillierte Kenntnisse über eine bestimmte Implementierung zu benötigen.


5
+1 für GUI-Toolkits ... und ich mag auch das Shapes-Beispiel mit einem Shape als Basis mit einem minimalen Draw () und den nachfolgenden Shapes mit benutzerdefinierten Draw ().
Yati Sagade

14

Mein reales Beispiel ist das Domänenmodell einer einfachen HR-Anwendung. Ich sage, dass wir eine Basisklasse namens Employee erstellen können , weil Manager natürlich auch Mitarbeiter sind.

public class Employee
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int Code { get; set; }

    public string GetInsuranceHistory()
    {
        // Retrieving insurance history based on employee code.
    }
}

Dann erkläre ich , dass Entwickler sind Mitarbeiter , Tester sind Mitarbeiter , Projektmanager sind Mitarbeiter . Somit können sie alle von der Mitarbeiterklasse erben .


2
Um die Vorteile der Vererbung aufzuzeigen, ist es möglicherweise interessant zu zeigen, wie sich Entwickler von Mitarbeitern unterscheiden. Wenn es keinen Unterschied gibt, muss überhaupt keine Entwicklerklasse erstellt werden.
David

3
Scheint, als Employeekönnte es sich auch um eine abstractKlasse handeln.
StuperUser

+1 Dies ist das Beispiel, das die meisten meiner Lehrer verwendet haben und das mir sehr gut gefallen hat. Es ergab einen klaren Sinn und gab ein reales Beispiel für die Verwendung der Vererbung.
David Peterman

18
Außer dass dies in der Praxis niemals funktioniert, weil es immer mindestens eine Person gibt, die sowohl a Developerals auch a sein muss Tester. Eine andere ähnliche Situation ist eine Kontaktdatenbank, in der Sie haben Customerund Supplier, aber wie jeder, der ein solches System erstellt hat, Ihnen sagen wird, gibt es immer einen Fall, in dem a Companybeides ist. Deshalb führen Sie die meisten dieser Beispiele in die falsche Richtung.
Scott Whitlock

11

Verkapseln, was variiert ... Zeigen Sie ihnen ein Muster für eine Vorlagenmethode . Es demonstriert die Nützlichkeit der Vererbung, indem gemeinsames Verhalten in eine Basisklasse eingefügt und unterschiedliches Verhalten in Unterklassen eingekapselt wird.

UI controlsund Streamssind auch ein sehr gutes Beispiel für die Nützlichkeit der Vererbung.


Ich denke, diese Fabrik wäre ein besseres Beispiel.
Let_Me_Be

1
@Let_Me_Be: Ich denke, die Beziehung zwischen Fabrik und Vererbung ist zu indirekt. Sicher, es erzeugt konkrete Typen und gibt abstrakte / Basistypen zurück, aber es könnte auch nur einen Schnittstellentyp zurückgeben! Imho, das ist nicht besser als das klassische Tierbeispiel.
Falcon

@Let_Me_Be: Eine abstrakte Factory ist auch ein recht komplexes Beispiel, das verschiedene Vererbungshierarchien umfasst (eine für die Elemente, eine für die Fabriken). Ich denke, es ist eine gute Verwendung der Vererbung, aber kein gutes und einfaches Beispiel.
Falcon

3

Merken

Jede Instanz eines Objekts ist ein konkretes Beispiel für die Nützlichkeit der Vererbung!

Wenn Sie spezifisch Klassenvererbung meinen , befinden Sie sich jetzt in der Welt der Taxonomien, und diese variieren drastisch je nach den Zielen des Systems, das sie verwendet. Das Beispiel Tiere / Säugetiere verwendet eine verbreitete und hoffentlich vertraute Taxonomie aus der Biologie, die jedoch (wie Sie bereits erwähnt haben) für die überwiegende Mehrheit der Programmierprobleme nahezu unbrauchbar ist.

Probieren Sie etwas Universelles aus: den Begriff eines Programms. Jedes Programm startet, läuft und endet. Jedes Programm hat einen Namen und optionale Befehlszeilenparameter. Daher wäre eine Basis-Programmklasse sehr nützlich, um die Ausführung zu starten, die Befehlszeilenargumente zu erfassen und zu verarbeiten, die Hauptlogik auszuführen und ordnungsgemäß herunterzufahren.

Aus diesem Grund bieten so viele objektorientierte Programmiersprachen eine Programmklasse oder etwas, das sich genau wie eine Programmklasse verhält.


Sie programmieren also ein Programm, das viele Programme enthält? :) Nach meiner Erfahrung sind Programmobjekte fast immer Singletons, die keine Vererbung haben, also sind sie nicht das beste Beispiel.
Keppla

@keppla: hast du jemals Java oder .NET benutzt? .NET hat eine explizite Program-Klasse, Java ist implizit. Sie sind keine Singletons
Steven A. Lowe

Ich habe Java verwendet, um Version 1.4.2. Damals gab es nur statische Leerstellen, also habe ich es ein wenig geändert. Was wäre ein typischer Grund, mehr als eine Instanz der Programmklasse zu haben?
keppla

@keppla: Java Static Void Main lässt implizit die Entry-Klasse das Programm darstellen. Jeder Benutzer, der Ihr Programm ausführt, erstellt eine neue Instanz davon. In diesem Moment werden drei Instanzen von Google Chrome ausgeführt, vier Word-Dokumente, drei Notizblöcke und zwei Windows-Explorer. Wenn sie alle Singletons wären, wäre ich niemals dazu in der Lage.
Steven A. Lowe

1
Ich denke, Sie dehnen die Definition ein wenig aus. class Programm { public static void main(String[] args) { system.out.println('hello world'); }}ist ein minimales Java-Programm. Wenn ich es nenne, gibt es keine Instanz von Program. Programm erbt von nichts. Wenn ich 3 Prozesse starte (wie Sie es mit crhome tun), kann es 3 Programme geben, aber in ihren einzelnen Speicherbereichen gibt es immer noch nur ein Programm. Imho, Singleton impliziert "Nur eine Instanz pro Prozess", nicht pro Maschine. In diesem Fall ist es unmöglich, Singletons zu erstellen. Nichts hindert Sie daran, Code zweimal auszuführen.
keppla

3

Ich arbeite mit Kameras bei der Arbeit. Wir haben Geräte, die mit verschiedenen Modellen verbunden sind, daher haben wir eine abstrakte "Kameraklasse" und jedes Modell erbt von dieser Klasse, um bestimmte Funktionen dieser Kamera zu unterstützen. Es ist ein Beispiel aus der Praxis und nicht schwer zu verstehen.


2
Dies könnte brechen , wenn Sie zB ein Modell , das sowohl eine ist Cameraund ein Phone(wie wir alle in unseren Taschen jetzt). Von welcher Basisklasse soll sie erben? Oder sollte es nicht einfach die ICameraund IPhone-Schnittstellen implementieren? (ha ha)
Scott Whitlock

2
@Scott: Sie können die IPhone-Schnittstelle nicht implementieren, oder Sie werden von Apple verklagt.
Mason Wheeler

3

Beispiel für chemische Elemente

Dies ist ein weiteres Beispiel aus meinem Gehirn:

Klasse Element_
{
    doppeltes Atomgewicht; // Atomgewicht des Elements
    double atomicNumber; // Ordnungszahl des Elements
    String Properties; // Eigenschaften des Elements
    // Andere, falls vorhanden
}


Klasse Isotope erweitert Element_ // Es können Isotope des Elements existieren
{
    doppelte Halbwertszeit;
   // Andere, falls vorhanden

}

2
Obwohl atomicNumber kann (sollte?) Wahrscheinlich eine Ganzzahl sein ...
Andrew

Ich würde dafür keine Vererbung verwenden. isotopeist kein Sonderfall von Elemenet. Ich hätte lieber eine ElementImmobilie auf Isotope.
CodesInChaos

2

Beispiele aus der realen Welt verstehen es fast immer falsch, weil sie Beispiele geben, bei denen es immer die Möglichkeit gibt, dass etwas beides ist, TypeAund TypeBdie Hierarchie mit nur einer Vererbung vieler Sprachen dies nicht zulässt.

Je mehr ich programmiere, desto weiter entferne ich mich von der Vererbung.

Sogar das Wort "erben" wird hier falsch verwendet. Zum Beispiel erben Sie ungefähr 50% der Merkmale Ihres Vaters und 50% der Merkmale Ihrer Mutter. In Wirklichkeit besteht Ihre DNA aus der Hälfte der DNA Ihres Vaters und der Hälfte der DNA Ihrer Mutter. Das liegt daran, dass die Biologie die Komposition der Vererbung vorgezogen hat , und das sollten Sie auch.

Das einfache Implementieren von Schnittstellen oder noch besser das "Duck Typing" plus Abhängigkeitsinjektion ist eine viel bessere Sache, um Menschen beizubringen, die mit objektorientierter Programmierung noch nicht vertraut sind.


1

Ich würde ihnen nur ein reales Beispiel zeigen. Beispielsweise leiten Sie in den meisten UI-Frameworks eine Art "Dialog" - oder "Window" - oder "Control" -Klasse ab, um Ihre eigene zu erstellen.


1

Ein gutes Beispiel ist die Vergleichsfunktion beim Sortieren:

template<class T>
class CompareInterface {
public:
   virtual bool Compare(T t1, T t2) const=0;
};
class FloatCompare : public CompareInterface<float> { };
class CompareImplementation : public FloatCompare {
public:
   bool Compare(float t1, float t2) const { return t1<t2; }
};
template<class T>
void Sort(T*array, int size, CompareInterface<T> &compare);

Das einzige Problem ist, dass die Neulinge zu oft denken, Leistung sei wichtiger als guter Code ...


0

Mein reales Beispiel ist ein Fahrzeug:

public class Vehicle
{
    public Vehicle(int doors, int wheels)
    {
        // I describe things that should be
        // established and "unchangeable" 
        // when the class is first "made"
        NumberOfDoors = doors;
        NumberOfWheels = wheels;
    }

    public void RollWindowsUp()
    {
        WindowsUp = true;
    }

    // I cover modifiers on properties to show
    // how to protect certain things from being
    // overridden
    public int NumberOfDoors { get; private set; }
    public int NumberOfWheels { get; private set; }

    public string Color { get; set; }
    public bool WindowsUp { get; set; }
    public int Speed { get; set; }
}

public class Car : Vehicle
{
    public Car : base(4, 4)
    {

    }
}

public class SemiTruck : Vehicle
{
    public SemiTruck : base(2, 18)
    {

    }
}

Dieses Beispiel kann so detailliert sein, wie Sie möchten, und es gibt alle Arten von Eigenschaften, die mit Fahrzeugen verknüpft sind, um die Verwendung von Modifikatoren zu erläutern, die Sie möglicherweise unterrichten möchten.


2
Ich habe es immer gehasst , Fahrzeuge als Beispiel zu verwenden, da es keinen neuen Programmierer näher bringt, zu verstehen, wie Vererbung zur Verbesserung von Code verwendet werden kann. Fahrzeuge sind immens komplizierte Maschinen, die den Nicht-Programmierer an eine Menge nicht-abstrakter Ideen erinnern. Der Versuch, dies im Code zu beschreiben, lässt den Durchschnittsanfänger glauben, dass viele Details im Beispiel fehlen, und vermittelt das Gefühl, dass sie nicht näher daran sind, etwas zum Laufen zu bringen. Ich sage dies aus Erfahrung, da ich mich genau so fühlte, als jemand versuchte, es mir mit Fahrzeugen zu erklären.
Riwalk

@ Stargazer712: Ich benutze Fahrzeuge in erster Linie, weil sie so kompliziert oder so einfach sein können, wie Sie möchten. Ich überlasse es dem Urteil des Lehrers, das Niveau seines Schülers zu bestimmen. Ich erklärte meiner Frau (die keine Programmiererfahrung hat) das grundlegende OOP anhand der einfachen Eigenschaften eines Fahrzeugs, in denen die allgemeinen Grundlagen beschrieben wurden. Alle Fahrzeuge haben Türen, alle Fahrzeuge haben Räder usw. Das Objektbeispiel kann nicht für einen schlechten Unterrichtsplan verantwortlich gemacht werden.
Joel Etherton

Ihre Frau hat nicht versucht, Code zu schreiben. Ich kann sehr sicher sagen , dass Fahrzeug Beispiele tat nichts , um mich Erbe verstehen zu helfen. Was auch immer Sie zur Beschreibung der Vererbung verwenden, es muss vollständig und praktisch sein . Das Ziel ist es nicht, es so zu beschreiben, dass ein Nicht-Programmierer es verstehen kann. Das Ziel ist es, es so zu beschreiben, dass ein Anfänger es verwenden kann, und der einzige Weg, dies zu tun, besteht darin, den Anfängern Beispiele zu zeigen, wie ein professioneller Programmierer es verwenden würde.
Riwalk

@ Stargazer712: Ich würde Ihre Unfähigkeit, die Vererbung zu verstehen, zunächst auf einen schlechten Unterrichtsplan zurückführen. Ich habe auch Fahrzeuge benutzt, um den Junioren, mit denen ich zusammenarbeite, die Vererbung zu erklären, und ich hatte nie ein Problem mit dem Konzept, das mir über den Weg läuft. Meiner Meinung nach ist ein Fahrzeugobjekt sowohl vollständig als auch praktisch, wenn ein Unterrichtsplan gründlich und richtig aufgebaut ist. 1 zufälliger Typ im Internet wird das nicht ändern, angesichts der rund 30 Praktikanten und Junior-Entwickler, denen ich OOP beigebracht habe. Wenn Ihnen das Fahrzeug nicht gefällt, stimmen Sie ab und fahren Sie fort.
Joel Etherton

Wie Sie möchten ...
Riwalk

0

Dieses Nicht-Säugetier-Nicht-Vogel-Nicht-Fisch-Beispiel könnte helfen:

public abstract class Person {

    /* this contains thing all persons have, like name, gender, home addr, etc. */

    public Object getHomeAddr() { ... }

    public Person getName() { ... }

}

public class Employee extends Person{

    /* It adds things like date of contract, salary, position, etc */

    public Object getAccount() { ... }

}

public abstract class Patient extends Person {
    /* It adds things like medical history, etc */
}

Dann

public static void main(String[] args) {

    /* you can send Xmas cards to patients and employees home addresses */

    List<Person> employeesAndPatients = Factory.getListOfEmployeesAndPatients();

    for (Person p: employeesAndPatients){
        sendXmasCard(p.getName(),p.getHomeAddr());
    }

    /* or you can proccess payment to employees */

    List<Employee> employees = Factory.getListOfEmployees();

    for (Employee e: employees){
        proccessPayment(e.getName(),e.getAccount());
    }       

}

HINWEIS: Verrate das Geheimnis nur nicht: Person erweitert Säugetier.


1
Arbeitet, bis einer Ihrer Mitarbeiter auch ein Patient ist.
Scott Whitlock

In diesem Fall ist es meiner Meinung nach sinnvoller, Patient und Mitarbeiter als Schnittstellen zu deklarieren, als abstrakte Klassen. Dies gibt Ihnen die Flexibilität, dass Person mehrere Schnittstellen implementiert.
Jin Kim

@ JinKim - Ich stimme vollkommen zu, das ist der bessere Ansatz.
Scott Whitlock

@ JinKim Sie sind nicht exklusiv. Sie behandeln eine Person zu einem bestimmten Zeitpunkt als Mitarbeiter oder als Patient, jedoch nicht zur gleichen Zeit. Zwei Schnittstellen sind in Ordnung, aber wann nennt man eine konkrete Klasse, die beide implementiert, EmployeePatient? Wie viele Kombinationen werden Sie haben?
Tulains Córdova

Sie können die konkrete Klasse so nennen, wie Sie möchten. Wenn der Code nur Mitarbeiter behandelt, deklarieren Sie die Referenz als Mitarbeiter. (dh Angestellter Angestellter = neue Person ();) Wenn der Code nur Patienten behandelt, geben Sie die Referenz als Patienten an. In seltenen Fällen möchten Sie eine Referenz direkt als konkrete Klasse deklarieren.
Jin Kim

0

Wie wäre es mit einer Hierarchie algebraischer Ausdrücke? Ist gut, weil es sowohl Vererbung als auch Zusammensetzung umfasst:

+--------------------+------------------------+
| Expression         |<------------------+    |
+--------------------+----------+        |    |
| + evaluate(): int  |<---+     |        |    |
+--------------------+    |     |        |    |
          ^               |     |        |    |
          |               |     |        |    |
   +--------------+  +---------------+  +-------------+  ...
   | Constant     |  | Negation      |  | Addition    |
   +--------------+  +---------------+  +-------------+
   | -value: int  |  |               |  |             |
   +--------------+  +---------------+  +-------------+
   | +evaluate()  |  | +evaluate()   |  | +evaluate() |
   | +toString()  |  | +toString()   |  | +toString() |
   +--------------+  +---------------+  +-------------+

   Addition(Constant(5), Negation(Addition(Constant(3),Constant(2))))
   (5 + -(3 + 2)) = 0

Mit Ausnahme der Stammausdruckskonstante sind alle anderen Ausdrücke ein Ausdruck und enthalten einen oder mehrere Ausdrücke.


-1

Ich werde Vögel als Beispiel verwenden

wie Huhn, Ente, Adler

Ich werde erklären, dass beide Klauen, Klauen und Flügel haben, aber ihre Attribute sind unterschiedlich.

Hühner können nicht fliegen, nicht schwimmen, können Würmer essen, können Getreide essen

Enten können nicht fliegen, schwimmen, Getreide essen, keine Würmer essen

Adler kann fliegen, nicht schwimmen, Würmer fressen, keine Körner fressen


4
Ich habe einmal gelesen, dass Komposition und Schnittstellen wahrscheinlich der beste Weg sind, um diese Art von Konzept zu vermitteln, dh fliegen, schwimmen usw.
dreza

Eine Ente kann nicht fliegen ?!
Adam Cameron

-3

Ihr typischer Rails-Clone bietet viele praktische Beispiele : Sie haben die (abstrakte) Basismodellklasse, die alle Datenmanipulationen kapselt, und Sie haben die Basiscontrollerklasse, die die gesamte HTTP-Kommunikation kapselt.


Möchten Sie herausfinden, warum diese Antwort schlecht ist?
Keppla
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.