1. Pegasus

Schauen wir uns das dritte Prinzip von OOP genauer an : Vererbung . Dies ist ein sehr interessantes Thema, das Sie oft verwenden werden. Für den Uneingeweihten ist Programmierung nicht von Magie zu unterscheiden. Beginnen wir also mit einer interessanten Analogie...;

Nehmen wir an, Sie sind ein Zauberer, der ein fliegendes Pferd erschaffen möchte. Einerseits könnten Sie versuchen, ein Pegasus zu beschwören. Da Pegasi aber in der Natur nicht vorkommen, wird dies sehr schwierig sein. Sie werden viel selbst tun müssen. Es ist viel einfacher, ein Pferd zu nehmen und seine Flügel zu beschwören.

In der Programmierung nennt man diesen Vorgang „Vererbung“. Angenommen, Sie müssen eine sehr komplexe Klasse schreiben. Es dauert lange, Code von Grund auf zu schreiben und dann alles lange zu testen, um nach Fehlern zu suchen. Warum den harten Weg gehen? Es ist besser, nachzusehen, ob eine solche Klasse bereits existiert.

Angenommen, Sie finden eine Klasse, deren Methoden 80 % der von Ihnen benötigten Funktionalität implementieren. Was machen Sie als nächstes damit? Sie können den Code einfach in Ihre Klasse kopieren. Diese Lösung hat jedoch mehrere Nachteile:

  1. Die von Ihnen gefundene Klasse ist möglicherweise bereits in Bytecode kompiliert und Sie haben möglicherweise keinen Zugriff auf ihren Quellcode.
  2. Der Quellcode der Klasse ist verfügbar, aber Sie arbeiten für ein Unternehmen, das für ein paar Milliarden verklagt werden könnte, wenn es auch nur 6 Zeilen Code eines anderen verwendet. Und dann wird Ihr Arbeitgeber Sie verklagen.
  3. Unnötige Duplizierung einer großen Codemenge. Wenn der Autor einer externen Klasse außerdem einen Fehler darin findet und ihn behebt, bleibt der Fehler bestehen.

Es gibt eine elegantere Lösung, für die kein legaler Zugriff auf den Code der Originalklasse erforderlich ist. In Java können Sie diese Klasse einfach als übergeordnete Klasse Ihrer Klasse deklarieren. Das entspricht dem Hinzufügen des Codes für diese Klasse zu Ihrem eigenen Code. Ihre Klasse sieht alle Daten und alle Methoden der übergeordneten Klasse. Sie können beispielsweise Folgendes tun: Wir erben „Pferd“ und fügen dann „Flügel“ hinzu, um ein „Pegasus“ zu erhalten.


2. Gemeinsame Basisklasse

Die Vererbung kann auch für andere Zwecke genutzt werden. Nehmen wir an, Sie haben zehn Klassen, die sehr ähnlich sind. Sie haben die gleichen Daten und Methoden. Sie können eine spezielle Basisklasse erstellen, die Daten (und die zugehörigen Methoden) in diese Basisklasse verschieben und diese zehn Klassen als Nachkommen deklarieren. Mit anderen Worten: Geben Sie in jeder Klasse an, dass ihre übergeordnete Klasse diese Basisklasse ist.

So wie die Vorteile der Abstraktion nur bei der Seitenkapselung zum Vorschein kommen, werden auch die Vorteile der Vererbung durch die Verwendung von Polymorphismus deutlich verstärkt. Aber das erfahren Sie etwas später. Heute werden wir uns einige Beispiele für die Verwendung der Vererbung ansehen.

Schachfiguren

Angenommen, wir schreiben ein Programm, das mit einem menschlichen Benutzer Schach spielt. Dementsprechend benötigen wir Klassen zur Darstellung der Stücke. Welche Klassen wären das?

Wenn Sie jemals Schach gespielt haben, lautet die offensichtliche Antwort: König, Dame, Läufer, Springer, Turm und Bauer.

Aber die Klassen selbst müssten immer noch Informationen zu jedem Stück speichern. Zum Beispiel die x- und y-Koordinaten und der Wert des Stücks. Schließlich sind einige Stücke wertvoller als andere.

Darüber hinaus bewegen sich die Teile unterschiedlich, was bedeutet, dass die Klassen unterschiedliche Verhaltensweisen implementieren. So könnten Sie sie als Klassen definieren:

class King
{
   int x;
   int y;
   int worth;

   void kingMove()
   {
     // Code that decides
     // how to move
     // the king
   }
}
class Queen
{
   int x;
   int y;
   int worth;

   void queenMove()
   {
     // Code that decides
     // how to move
     // the queen
   }
}
class Rook
{
   int x;
   int y;
   int worth;

   void rookMove()
   {
     // Code that decides
     // how to move
     // the rook
   }
}
class Knight
{
   int x;
   int y;
   int worth;

   void knightMove()
   {
     // Code that decides
     // how to move
     // the knight
   }
}
class Bishop
{
   int x;
   int y;
   int worth;

   void bishopMove()
   {
     // Code that decides
     // how to move
     // the bishop
   }
}
class Pawn
{
   int x;
   int y;
   int worth;

   void pawnMove()
   {
     // Code that decides
     // how to move
     // the pawn
   }
}

Dies ist eine sehr primitive Beschreibung von Schachfiguren.

Gemeinsame Basisklasse

Und so können Sie die Codemenge mithilfe der Vererbung reduzieren. Wir können die gemeinsamen Methoden und Daten in einer gemeinsamen Klasse zusammenfassen. Wir nennen es ChessItem. Es macht keinen Sinn, Objekte zu erstellen ChessItem class, da die Klasse keiner Schachfigur entspricht . Dennoch wird sich die Klasse als sehr nützlich erweisen:

class King extends ChessItem
{
   void kingMove()
   {
     // Code that decides
     // how to move the king
   }
}
class Queen extends ChessItem
{
   void queenMove()
   {
     // Code that decides
     // how to move the queen
   }
}
class Rook extends ChessItem
{
   void rookMove()
   {
     // Code that decides
     // how to move the rook
   }
}
class ChessItem
{
   int x;
   int y;
   int worth;
}
class Knight extends ChessItem
{
   void knightMove()
   {
     // Code that decides
     // how to move the knight
   }
}
class Bishop extends ChessItem
{
   void bishopMove()
   {
     // Code that decides
     // how to move the bishop
   }
}
class Pawn extends ChessItem
{
   void pawnMove()
   {
     // Code that decides
     // how to move the pawn
   }
}

Dies ist eine großartige Möglichkeit, den Code für ähnliche Objekte zu vereinfachen. Die Vorteile machen sich insbesondere dann bemerkbar, wenn das Projekt Tausende verschiedene Objekte und Hunderte Klassen enthält. Mit richtig ausgewählten übergeordneten (Basis-)Klassen können Sie nicht nur die Logik erheblich vereinfachen, sondern auch den Code um das Zehnfache reduzieren.


3. Klassenvererbung –extends

Was ist also nötig, um eine Klasse zu erben? Damit eine Klasse eine andere erbt, müssen Sie das extendsSchlüsselwort nach der Deklaration der untergeordneten Klasse und dann den Namen der übergeordneten Klasse schreiben. Normalerweise sieht es ungefähr so ​​aus:

class Descendant extends Parent

Dies ist, was Sie schreiben müssen, wenn Sie die Descendant-Klasse deklarieren. Eine Klasse kann übrigens nur eine Klasse erben.

Auf dem Bild sehen wir, dass eine Kuh ein Schwein geerbt hat, das ein Huhn geerbt hat, das ein Ei geerbt hat. Nur ein Elternteil! Eine solche Vererbung ist nicht immer logisch. Aber wenn man nur ein Schwein hat und wirklich eine Kuh braucht, können Programmierer oft dem Drang nicht widerstehen, aus einem Schwein eine Kuh zu machen.

In Java gibt es keine Mehrfachvererbung: Eine Klasse kann nicht zwei Klassen erben. Jede Klasse kann nur eine übergeordnete Klasse haben. Wenn keine übergeordnete Klasse angegeben ist, ist die übergeordnete Klasse Object.

Allerdings verfügt Java über eine Mehrfachvererbung von Schnittstellen. Dadurch wird das Problem etwas gemildert. Wir werden etwas später über Schnittstellen sprechen, aber zunächst wollen wir uns weiter mit der Vererbung befassen.