1. Pegasus

Laten we dieper ingaan op het derde principe van OOP : overerving . Dit is een zeer interessant onderwerp dat u vaak zult gebruiken. Voor niet-ingewijden is programmeren niet te onderscheiden van magie. Dus laten we beginnen met een interessante analogie...;

Laten we zeggen dat je een tovenaar bent die een vliegend paard wil maken. Aan de ene kant zou je kunnen proberen een pegasus te toveren. Maar omdat pegasi niet in de natuur voorkomt, zal dit erg moeilijk worden. Je zult veel zelf moeten doen. Het is veel gemakkelijker om een ​​paard te nemen en zijn vleugels te toveren.

Bij het programmeren wordt dit proces "overerving" genoemd. Stel dat u een zeer complexe klasse moet schrijven. Het kost veel tijd om vanuit het niets code te schrijven en vervolgens alles lang te testen op fouten. Waarom de moeilijke weg inslaan? Het is beter om te kijken of zo'n klasse al bestaat.

Stel dat u een klasse vindt waarvan de methoden 80% van de functionaliteit implementeren die u nodig hebt. Wat doe je er vervolgens mee? Je zou de code gewoon naar je klas kunnen kopiëren. Maar deze oplossing heeft verschillende nadelen:

  1. De klasse die u vindt, is mogelijk al in bytecode gecompileerd en u hebt mogelijk geen toegang tot de broncode.
  2. De broncode van de class is beschikbaar, maar je werkt voor een bedrijf dat voor een paar miljard kan worden aangeklaagd voor het gebruik van zelfs maar 6 regels code van iemand anders. En dan klaagt je werkgever je aan.
  3. Onnodige duplicatie van een grote hoeveelheid code. Bovendien, als de auteur van een externe klasse er een bug in vindt en deze repareert, heb je de bug nog steeds.

Er is een elegantere oplossing en hiervoor is geen legale toegang tot de code van de oorspronkelijke klasse vereist. In Java kunt u die klasse eenvoudigweg declareren als de ouder van uw klasse. Dat komt overeen met het toevoegen van de code voor die klasse aan uw eigen code. Uw klasse ziet alle gegevens en alle methoden van de bovenliggende klasse. U kunt dit bijvoorbeeld doen: we erven "paard" en voegen vervolgens "vleugels" toe om een ​​"pegasus" te krijgen


2. Gemeenschappelijke basisklasse

Overerving kan ook voor andere doeleinden worden gebruikt. Laten we zeggen dat je tien klassen hebt die erg op elkaar lijken. Ze hebben dezelfde gegevens en methoden. U kunt een speciale basisklasse maken, de gegevens (en bijbehorende methoden) naar deze basisklasse verplaatsen en die tien klassen als afstammelingen verklaren. Met andere woorden, geef in elke klasse aan dat de bovenliggende klasse deze basisklasse is.

Net zoals de voordelen van abstractie alleen worden onthuld door zijdelingse inkapseling, zo worden ook de voordelen van overerving veel groter bij gebruik van polymorfisme. Maar daar leer je later meer over. Vandaag zullen we verschillende voorbeelden bekijken van het gebruik van overerving.

Schaakstukken

Stel dat we een programma schrijven dat schaakt met een menselijke gebruiker. Daarom hebben we klassen nodig om de stukken weer te geven. Welke klassen zouden het zijn?

Als je ooit hebt geschaakt, is het voor de hand liggende antwoord: koning, vrouw, loper, paard, toren en pion.

Maar de klassen zelf zouden nog steeds informatie over elk stuk moeten opslaan. Bijvoorbeeld de x- en y-coördinaten en de waarde van het stuk. Sommige stukken zijn immers meer waard dan andere.

Bovendien bewegen de stukken anders, wat betekent dat de klassen ander gedrag zullen implementeren. Hier ziet u hoe u ze als klassen kunt definiëren:

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

Dit is een zeer primitieve beschrijving van schaakstukken.

Gemeenschappelijke basisklasse

En hier ziet u hoe u overerving kunt gebruiken om de hoeveelheid code te verminderen. We kunnen de gemeenschappelijke methoden en gegevens in een gemeenschappelijke klasse brengen. We zullen het noemen ChessItem. Het heeft geen zin om objecten van de te maken ChessItem class, aangezien de klasse met geen enkel schaakstuk overeenkomt . Dat gezegd hebbende, zal de klasse erg nuttig blijken te zijn:

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

Dit is een geweldige manier om de code voor vergelijkbare objecten te vereenvoudigen. De voordelen zijn vooral merkbaar wanneer er duizenden verschillende objecten en honderden klassen in het project zijn. Dus met correct geselecteerde ouderklassen (basisklassen) kunt u niet alleen de logica aanzienlijk vereenvoudigen, maar ook de code vertienvoudigen.


3. Klassenovererving —extends

Dus wat is er nodig om een ​​klasse te erven? Om de ene klasse een andere te laten erven, moet u het extendstrefwoord achter de declaratie van de onderliggende klasse schrijven en vervolgens de naam van de bovenliggende klasse. Het ziet er meestal ongeveer zo uit:

class Descendant extends Parent

Dit is wat u moet schrijven bij het declareren van de klasse Descendant. Overigens kan een klasse slechts één klasse overerven.

Op de foto zien we dat een koe een varken erfde, dat een kip erfde, die een ei erfde. Slechts één ouder! Zo'n erfenis is niet altijd logisch. Maar als je alleen maar een varken hebt en je echt een koe nodig hebt, kunnen programmeurs vaak de neiging niet weerstaan ​​om van een varken een koe te maken.

Java heeft geen meervoudige overerving: een klasse kan niet twee klassen erven. Elke klasse kan slechts één bovenliggende klasse hebben. Als er geen bovenliggende klasse is opgegeven, is de bovenliggende klasse Object.

Dat gezegd hebbende, Java heeft meerdere overerving van interfaces. Dit verzacht het probleem enigszins. We zullen het later hebben over interfaces, maar laten we nu doorgaan met het onderzoeken van overerving.