1. Pegasus

Lad os tage et dybere kig på det tredje princip i OOP : arv . Dette er et meget interessant emne, som du vil bruge ofte. For de uindviede kan programmering ikke skelnes fra magi. Så lad os starte med en interessant analogi...;

Lad os sige, at du er en troldmand, der ønsker at skabe en flyvende hest. På den ene side kan du prøve at fremtrylle en pegasus. Men fordi pegasi ikke findes i naturen, vil dette være meget svært. Du skal selv gøre meget. Det er meget nemmere at tage en hest og trylle dens vinger.

I programmering kaldes denne proces for "arv". Antag, at du skal skrive en meget kompleks klasse. Det tager lang tid at skrive kode fra bunden og derefter teste alt i lang tid for at lede efter fejl. Hvorfor gå den hårde vej? Det er bedre at se, om en sådan klasse allerede eksisterer.

Antag, at du finder en klasse, hvis metoder implementerer 80% af den funktionalitet, du har brug for. Hvad gør du så med det? Du kan bare kopiere dens kode ind i din klasse. Men denne løsning har flere ulemper:

  1. Klassen, du finder, er muligvis allerede kompileret til bytekode, og du har muligvis ikke adgang til dens kildekode.
  2. Klassens kildekode er tilgængelig, men du arbejder for en virksomhed, der kunne blive sagsøgt for et par milliarder for at bruge selv 6 linjer af en andens kode. Og så vil din arbejdsgiver sagsøge dig.
  3. Unødvendig duplikering af en stor mængde kode. Derudover, hvis forfatteren af ​​en ekstern klasse finder en fejl i den og retter den, vil du stadig have fejlen.

Der er en mere elegant løsning, og den kræver ikke at få lovlig adgang til den originale klasses kode. I Java kan du blot erklære den klasse som forælder til din klasse. Det vil svare til at tilføje koden for den pågældende klasse til din egen kode. Din klasse vil se alle data og alle metoderne for den overordnede klasse. For eksempel kan du gøre dette: vi arver "hest" og tilføjer derefter "vinger" for at få en "pegasus"


2. Fælles basisklasse

Arv kan også bruges til andre formål. Lad os sige, at du har ti klasser, der ligner hinanden meget. De har de samme data og metoder. Du kan oprette en speciel basisklasse, flytte dataene (og tilknyttede metoder) til denne basisklasse og erklære disse ti klasser for at være efterkommere. Med andre ord, i hver klasse angiver, at dens overordnede klasse er denne basisklasse.

Ligesom fordelene ved abstraktion kun afsløres langs sideindkapsling, så er fordelene ved nedarvning også meget forbedret, når man bruger polymorfi. Men det lærer du om lidt senere. I dag skal vi se på flere eksempler på brug af arv.

Skakbrikker

Antag, at vi skriver et program, der spiller skak med en menneskelig bruger. Derfor har vi brug for klasser til at repræsentere brikkerne. Hvilke klasser ville de være?

Hvis du nogensinde har spillet skak, er det åbenlyse svar Konge, Dronning, Biskop, Ridder, Rook og Bonde.

Men klasserne selv skulle stadig gemme oplysninger om hvert stykke. For eksempel x- og y-koordinaterne og værdien af ​​brikken. Nogle stykker er trods alt mere værdifulde end andre.

Derudover bevæger brikkerne sig forskelligt, hvilket betyder, at klasserne vil implementere forskellig adfærd. Sådan kan du definere dem som klasser:

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

Dette er en meget primitiv beskrivelse af skakbrikker.

Fælles basisklasse

Og her er, hvordan du kan bruge arv til at reducere mængden af ​​kode. Vi kan bringe de gængse metoder og data ind i en fælles klasse. Vi kalder det ChessItem. Det nytter ikke at skabe objekter af ChessItem class, da klassen ikke svarer til nogen skakbrik . Når det er sagt, vil klassen vise sig meget nyttig:

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

Dette er en fantastisk måde at forenkle koden for lignende objekter. Fordelene er især mærkbare, når der er tusindvis af forskellige objekter og hundredvis af klasser i projektet. Så korrekt udvalgte overordnede (base) klasser lader dig ikke kun i høj grad forenkle logikken, men også reducere koden ti gange.


3. Klassearv —extends

Så hvad skal der til for at arve en klasse? For at en klasse skal arve en anden, skal du skrive nøgleordet extendsefter den underordnede klasseerklæring og derefter skrive navnet på den overordnede klasse. Det ser normalt sådan ud:

class Descendant extends Parent

Dette er, hvad du skal skrive, når du erklærer Descendant-klassen. En klasse kan i øvrigt kun arve én klasse.

På billedet ser vi, at en ko har arvet en gris, som har arvet en kylling, som har arvet et æg. Kun én forælder! En sådan arv er ikke altid logisk. Men når alt, hvad du har, er en gris, og du virkelig har brug for en ko, kan programmører ofte ikke modstå trangen til at lave en ko af en gris.

Java har ikke multipel nedarvning: en klasse kan ikke arve to klasser. Hver klasse kan kun have én overordnet klasse. Hvis der ikke er angivet en overordnet klasse, er den overordnede klasse Object.

Når det er sagt, har Java flere grænseflader. Dette afhjælper problemet lidt. Vi vil tale om grænseflader lidt senere, men lad os nu fortsætte med at udforske arv.