„Bună, Amigo! Acum iată un subiect pe care cred că o să-l folosești foarte mult. Vorbesc despre moștenire.

Pentru cei neinițiați, programarea este ca o magie. Asa ca sa incep cu o analogie...

Să presupunem că ești un magician care vrea să creeze un cal zburător. Ai putea încerca să invoci un Pegasus. Dar din moment ce caii zburători nu apar în mod natural, veți avea un moment foarte greu. Ai avea mult de lucru. Ar fi mult mai ușor să începi cu un cal și să invoci niște aripi.

Moştenire.  Avantajele moștenirii - 1

În programare, numim acest proces „moștenire” . Să presupunem că trebuie să scrieți o clasă foarte complexă. Puteți petrece mult timp scriind cod de la zero și apoi efectuați teste lungi pentru a găsi erori. Dar de ce o faci pe calea grea? Este mai bine să te uiți în jur și să vezi dacă clasa pe care o cauți există deja?

Să presupunem că găsiți o clasă care implementează 80% din funcționalitatea de care aveți nevoie. Puteți doar să copiați codul său în clasa dvs. Dar asta ar avea mai multe dezavantaje:

1) Clasa pe care o găsiți ar putea fi deja compilată în bytecode. Este posibil să nu aveți acces la codul sursă.

2) S-ar putea să aveți codul sursă pentru curs, dar să lucrați și la o companie care ar putea fi dat în judecată pentru câteva miliarde dacă folosiți chiar și 6 rânduri din codul altcuiva. Și apoi te vor da în judecată.

3) Acest lucru duce la duplicarea inutilă a multor coduri. Și dacă autorul celeilalte clase găsește o eroare și o remediază, încă mai aveți eroarea.

Există o soluție mai elegantă care nu necesită obținerea permisiunii legale pentru codul clasei originale. În Java, puteți declara pur și simplu cealaltă clasă ca părinte a clasei dvs. Acest lucru este echivalent cu adăugarea codului acelei clase la propria clasă. Toate datele și metodele clasei părinte vor apărea în clasa dvs. De exemplu, puteți moșteni de la un „cal”, adăugați „aripi” și obțineți un „Pegas”.

Moştenire.  Avantajele moștenirii - 2

"Foarte interesant. Te rog, continuă."

„Moștenirea are și alte utilizări. Să presupunem că aveți zece clase care sunt foarte asemănătoare. Au date și metode care se potrivesc. Puteți crea o clasă de bază specială, mutați datele (și metodele asociate) în clasa de bază și aveți acele zece clase. moștenește de la ea. Cu alte cuvinte, pentru fiecare clasă, indicați că are o clasă părinte, cunoscută și ca clasă de bază."

"Așa cum avantajele abstractizării sunt dezvăluite cu adevărat doar în legătură cu încapsularea, avantajele moștenirii sunt amplificate de polimorfism. Dar despre asta vă voi spune mâine. Astăzi să ne uităm la câteva exemple de moștenire."

— Să presupunem că scriem un program de șah. Vom avea nevoie de cursuri pentru piesele de șah. Ce cursuri ai sugera, Amigo?

„Rege, Regina, Episcop, Cavaler, Turn și Pion”.

"Foarte bine. Nu ai ratat nimic."

„Și ce date ați sugera să stocați în aceste clase?”

"Poziția fiecărei piese (x și y) și valoarea fiecărei piese. La urma urmei, unele piese sunt mai valoroase decât altele."

— Și care sunt diferențele dintre aceste clase?

"Ei diferă în modul în care mișcă piesele. În comportamentul lor."

"Da. Le-ai putea defini ca astfel de clase:"

class King
{
int x;
int y;
int worth;
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen
{
int x;
int y;
int worth;
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook
{
int x;
int y;
int worth;
void rookMove()
{
//code that defines,
//how the rook moves
}
}
class Knight
{
int x;
int y;
int worth;
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop
{
int x;
int y;
int worth;
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn
{
int x;
int y;
int worth;
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

— Da, exact așa l-aș scrie.

„Dar uitați-vă la modul în care ați putea folosi moștenirea pentru a scrie mai puțin cod. Putem muta metode și date identice într-o clasă comună. Să o numim ChessItem. Nu are sens să creați obiecte ChessItem, deoarece acestea nu corespund niciunui obiect. piesă de șah. Dar clasa ar fi extrem de utilă:"

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

"Ce interesant!"

"Absolut! Beneficiul este deosebit de mare în proiectele care conțin mii de obiecte diferite și sute de clase. În acest caz, clasele alese corect nu numai că pot simplifica semnificativ logica, ci și pot reduce codul necesar cu un factor de zece."

„Deci ce trebuie să faci pentru a moșteni o clasă?”

„După declararea unei clase, folosim cuvântul cheie „ extinde ”, urmat de numele clasei părinte. Puteți moșteni doar de la o clasă.

Moştenire.  Avantajele moștenirii - 3

Imaginea arată o „vacă” care a moștenit de la un „porc”. «Porcul» moștenește de la «găină», iar «găina» moștenește de la «ou». Fiecare clasă are un singur părinte! O astfel de moștenire nu este întotdeauna logică. Dacă ai doar un porc, dar chiar ai nevoie de o vacă, programatorii nu pot rezista adesea dorinței de a face o „vacă” din „porc”.

"Dar dacă vreau să moștenesc din două clase? Pot face ceva?!"

„Nu chiar. Clasele Java nu acceptă moștenirea multiplă a implementării: o clasă poate avea doar o singură clasă părinte. Dar există moștenire multiplă de tip, ceea ce înseamnă că o clasă poate implementa mai mult de o interfață. Acest lucru atenuează ușor problema. "

— Înțeleg. Și ce este o interfață?

„Îți voi vorbi mâine despre interfețe. Deocamdată, haideți să continuăm să cercetăm moștenirea.”