1. Pegasus

Låt oss ta en djupare titt på den tredje principen för OOP : arv . Detta är ett mycket intressant ämne som du kommer att använda ofta. För den oinvigde går programmering inte att skilja från magi. Så låt oss börja med en intressant analogi...;

Låt oss säga att du är en trollkarl som vill skapa en flygande häst. Å ena sidan kan du prova att trolla fram en pegasus. Men eftersom pegasi inte finns i naturen blir detta väldigt svårt. Du kommer att behöva göra mycket själv. Det är mycket lättare att ta en häst och trolla dess vingar.

Inom programmering kallas denna process för "arv". Anta att du behöver skriva en mycket komplex klass. Det tar lång tid att skriva kod från grunden och sedan testa allt under lång tid för att leta efter fel. Varför gå den hårda vägen? Det är bättre att se om en sådan klass redan finns.

Anta att du hittar en klass vars metoder implementerar 80 % av den funktionalitet du behöver. Vad gör du med det härnäst? Du kan bara kopiera dess kod till din klass. Men denna lösning har flera nackdelar:

  1. Klassen du hittar kanske redan är kompilerad till bytecode, och du kanske inte har tillgång till dess källkod.
  2. Klassens källkod är tillgänglig, men du arbetar för ett företag som skulle kunna stämmas för ett par miljarder för att ha använt till och med 6 rader av någon annans kod. Och sedan kommer din arbetsgivare att stämma dig.
  3. Onödig dubblering av en stor mängd kod. Dessutom, om författaren till en extern klass hittar en bugg i den och fixar den, har du fortfarande felet.

Det finns en mer elegant lösning, och den kräver inte att man får laglig tillgång till den ursprungliga klassens kod. I Java kan du helt enkelt deklarera den klassen som förälder till din klass. Det kommer att motsvara att lägga till koden för den klassen till din egen kod. Din klass kommer att se all data och alla metoder för den överordnade klassen. Du kan till exempel göra så här: vi ärver "häst" och lägger sedan till "vingar" för att få en "pegasus"


2. Gemensam basklass

Arv kan också användas för andra ändamål. Låt oss säga att du har tio klasser som är väldigt lika. De har samma data och metoder. Du kan skapa en speciell basklass, flytta data (och associerade metoder) till denna basklass och förklara dessa tio klasser som avkomlingar. Med andra ord, i varje klass ange att dess överordnade klass är denna basklass.

Precis som fördelarna med abstraktion endast avslöjas längs sidoinkapsling, så är fördelarna med arv mycket förstärkta när man använder polymorfism. Men det lär du dig om lite senare. Idag ska vi titta på flera exempel på användning av arv.

Schackpjäser

Anta att vi skriver ett program som spelar schack med en mänsklig användare. Därför behöver vi klasser för att representera bitarna. Vilka klasser skulle de vara?

Om du någonsin har spelat schack är det självklara svaret kung, drottning, biskop, riddare, torn och bonde.

Men klasserna själva skulle fortfarande behöva lagra information om varje del. Till exempel x- och y-koordinaterna och värdet på pjäsen. När allt kommer omkring är vissa bitar mer värda än andra.

Dessutom rör sig pjäserna olika, vilket gör att klasserna kommer att implementera olika beteenden. Så här kan du definiera 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
   }
}

Detta är en mycket primitiv beskrivning av schackpjäser.

Gemensam basklass

Och här är hur du kan använda arv för att minska mängden kod. Vi kan föra de vanliga metoderna och data till en gemensam klass. Vi kommer att kalla det ChessItem. Det är ingen idé att skapa objekt av ChessItem class, eftersom klassen inte motsvarar någon schackpjäs . Som sagt, klassen kommer att visa sig vara väldigt användbar:

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

Detta är ett bra sätt att förenkla koden för liknande objekt. Fördelarna är särskilt märkbara när det finns tusentals olika föremål och hundratals klasser i projektet. Så korrekt valda överordnade (bas) klasser låter dig inte bara avsevärt förenkla logiken, utan också reducera koden tio gånger.


3. Klassarv —extends

Så vad krävs för att ärva en klass? För att en klass ska ärva en annan måste du skriva extendsnyckelordet efter den underordnade klassdeklarationen och sedan skriva namnet på den överordnade klassen. Det brukar se ut ungefär så här:

class Descendant extends Parent

Detta är vad du behöver skriva när du deklarerar Descendant-klassen. Förresten, en klass kan bara ärva en klass.

På bilden ser vi att en ko ärvde en gris, som ärvde en kyckling, som ärvde ett ägg. Endast en förälder! Sådant arv är inte alltid logiskt. Men när allt du har är en gris och du verkligen behöver en ko, kan programmerare ofta inte motstå lusten att göra en ko av en gris.

Java har inte multipelt arv: en klass kan inte ärva två klasser. Varje klass kan bara ha en förälderklass. Om ingen överordnad klass anges är den överordnade klassen Object.

Som sagt, Java har flera arv av gränssnitt. Detta mildrar problemet något. Vi kommer att prata om gränssnitt lite senare, men låt oss nu fortsätta att utforska arv.