1. Пегас

Нека разгледаме по-задълбочено третия принцип на ООП : наследяване . Това е много интересна тема, която ще използвате често. За непосветените програмирането е неразличимо от магията. Така че нека започнем с една интересна аналогия...;

Да приемем, че сте магьосник, който иска да създаде летящ кон. От една страна, можете да опитате да измислите пегас. Но тъй като пегасите не съществуват в природата, това ще бъде много трудно. Вие сами ще трябва да направите много. Много по-лесно е да вземете кон и да извикате крилете му.

В програмирането този процес се нарича "наследяване". Да предположим, че трябва да напишете много сложен клас. Отнема много време да напишете code от нулата и след това да тествате всичко дълго време, за да търсите грешки. Защо да вървим по трудния път? По-добре е да проверите дали вече съществува такъв клас.

Да предположим, че намерите клас, чиито методи изпълняват 80% от функционалността, от която се нуждаете. Какво правите с него след това? Можете просто да копирате неговия code във вашия клас. Но това решение има няколко недостатъка:

  1. Класът, който намерите, може вече да е компorран в byte code и може да нямате достъп до изходния му code.
  2. Изходният code на класа е достъпен, но вие работите за компания, която може да бъде съдена за няколко мorарда за използване дори на 6 реда от codeа на някой друг. И тогава вашият работодател ще ви съди.
  3. Ненужно дублиране на голямо количество code. Освен това, ако авторът на външен клас открие грешка в него и я поправи, вие пак ще имате грешката.

Има по-елегантно решение и то не изисква получаване на легален достъп до codeа на оригиналния клас. В Java можете просто да декларирате този клас като родител на вашия клас. Това ще бъде еквивалентно на добавяне на codeа за този клас към вашия собствен code. Вашият клас ще види всички данни и всички методи на родителския клас. Например, можете да направите това: наследяваме „кон“ и след това добавяме „крила“, за да получим „пегас“


2. Общ базов клас

Наследството може да се използва и за други цели. Да кажем, че имате десет класа, които са много сходни. Те имат едни и същи данни и методи. Можете да създадете специален базов клас, да преместите данните (и свързаните с тях методи) в този базов клас и да декларирате тези десет класа като наследници. С други думи, във всеки клас посочете, че неговият родителски клас е този базов клас.

Точно Howто предимствата на абстракцията се разкриват само покрай страничното капсулиране, така и предимствата на наследяването са значително подобрени при използване на полиморфизъм. Но ще научите за това малко по-късно. Днес ще разгледаме няколко примера за използване на наследяване.

Фигури за шах

Да предположим, че пишем програма, която играе шах с човешки потребител. Съответно имаме нужда от класове, които да представят парчетата. Какви класове биха бor?

Ако някога сте играли шах, очевидният отговор е цар, дама, епископ, кон, топ и пешка.

Но самите класове все пак ще трябва да съхраняват информация за всяко парче. Например координатите x и y и стойността на парчето. В крайна сметка някои парчета са по-ценни от други.

В допълнение, фигурите се движат по различен начин, което означава, че класовете ще прилагат различно поведение. Ето How можете да ги дефинирате като класове:

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

Това е много примитивно описание на шахматните фигури.

Общ базов клас

И ето How можете да използвате наследяването, за да намалите количеството code. Можем да съберем общите методи и данни в общ клас. Ще го наречем ChessItem. Няма смисъл да се създават обекти от ChessItem class, тъй като класът не съответства на нито една шахматна фигура . Въпреки това класът ще се окаже много полезен:

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

Това е чудесен начин за опростяване на codeа за подобни обекти. Ползите са особено забележими, когато в проекта има хиляди различни обекти и стотици класове. Така че правилно избраните родителски (базови) класове ви позволяват не само значително да опростите логиката, но и да намалите codeа десетократно.


3. Наследяване на класовеextends

И така, Howво е необходимо, за да се наследи клас? За да може един клас да наследи друг, трябва да напишете extendsключовата дума след декларацията на дъщерния клас и след това да напишете името на родителския клас. Обикновено изглежда по следния начин:

class Descendant extends Parent

Това е, което трябва да напишете, когато декларирате класа Descendant. Между другото, един клас може да наследи само един клас.

На снимката виждаме, че една крава е наследила прасе, което е наследило пиле, което е наследило яйце. Само един родител! Такова наследяване не винаги е логично. Но когато всичко, което имате, е прасе и наистина имате нужда от крава, програмистите често не могат да устоят на желанието да направят крава от прасе.

Java няма множествено наследяване: един клас не може да наследи два класа. Всеки клас може да има само един родителски клас. Ако не е указан родителски клас, родителският клас е Object.

Въпреки това Java има множество наследства на интерфейси. Това леко смекчава проблема. Ще говорим за интерфейсите малко по-късно, но засега нека продължим да изследваме наследяването.