1. Pegaso
Diamo uno sguardo più approfondito al terzo principio dell'OOP : l' ereditarietà . Questo è un argomento molto interessante che userai spesso. Per chi non lo sapesse, la programmazione è indistinguibile dalla magia. Quindi iniziamo con un'interessante analogia...;
Diciamo che sei un mago che vuole creare un cavallo volante. Da un lato, potresti provare a evocare un pegaso. Ma poiché i pegasi non esistono in natura, sarà molto difficile. Dovrai fare molto da solo. È molto più facile prendere un cavallo ed evocare le sue ali.
In programmazione, questo processo è chiamato "ereditarietà". Supponiamo di dover scrivere una classe molto complessa. Ci vuole molto tempo per scrivere il codice da zero e quindi testare tutto a lungo per cercare errori. Perché andare nel modo più duro? È meglio controllare se esiste già una classe del genere.
Supponiamo di trovare una classe i cui metodi implementano l'80% delle funzionalità necessarie. Cosa ne fai dopo? Potresti semplicemente copiare il suo codice nella tua classe. Ma questa soluzione presenta diversi inconvenienti:
- La classe che trovi potrebbe essere già compilata in bytecode e potresti non avere accesso al suo codice sorgente.
- Il codice sorgente della classe è disponibile, ma tu lavori per un'azienda che potrebbe essere citata in giudizio per un paio di miliardi per aver utilizzato anche solo 6 righe del codice di qualcun altro. E poi il tuo datore di lavoro ti farà causa.
- Duplicazione non necessaria di una grande quantità di codice. Inoltre, se l'autore di una classe esterna trova un bug in essa e lo corregge, avrai ancora il bug.
Esiste una soluzione più elegante e non richiede l'accesso legale al codice della classe originale. In Java, puoi semplicemente dichiarare quella classe come genitore della tua classe. Ciò equivarrà ad aggiungere il codice per quella classe al tuo codice. La tua classe vedrà tutti i dati e tutti i metodi della classe genitore. Ad esempio, puoi fare questo: ereditiamo "cavallo" e poi aggiungiamo "ali" per ottenere un "pegaso"
2. Classe base comune
L'ereditarietà può essere utilizzata anche per altri scopi. Supponiamo che tu abbia dieci classi molto simili. Hanno gli stessi dati e metodi. È possibile creare una classe base speciale, spostare i dati (ei metodi associati) in questa classe base e dichiarare discendenti quelle dieci classi. In altre parole, in ogni classe indicare che la sua classe genitore è questa classe base.
Proprio come i vantaggi dell'astrazione si rivelano solo insieme all'incapsulamento laterale, così anche i vantaggi dell'ereditarietà sono molto migliorati quando si usa il polimorfismo. Ma lo scoprirai un po 'più tardi. Oggi esamineremo diversi esempi di utilizzo dell'ereditarietà.
Pezzi degli scacchi
Supponiamo di scrivere un programma che gioca a scacchi con un utente umano. Di conseguenza, abbiamo bisogno di classi per rappresentare i pezzi. Che classi sarebbero?
Se hai mai giocato a scacchi, la risposta ovvia è Re, Regina, Alfiere, Cavaliere, Torre e Pedone.
Ma le classi stesse avrebbero comunque bisogno di memorizzare informazioni su ogni pezzo. Ad esempio, le coordinate x e y e il valore del pezzo. Dopo tutto, alcuni pezzi sono più preziosi di altri.
Inoltre, i pezzi si muovono in modo diverso, il che significa che le classi implementeranno un comportamento diverso. Ecco come potresti definirli come classi:
|
|
|
|
|
|
Questa è una descrizione molto primitiva dei pezzi degli scacchi.
Classe base comune
Ed ecco come puoi usare l'ereditarietà per ridurre la quantità di codice. Possiamo portare i metodi e i dati comuni in una classe comune. Lo chiameremo ChessItem
. Non ha senso creare oggetti di ChessItem class
, poiché la classe non corrisponde a nessun pezzo degli scacchi . Detto questo, la classe si rivelerà molto utile:
|
|
|
|
||
|
|
|
Questo è un ottimo modo per semplificare il codice per oggetti simili. I vantaggi sono particolarmente evidenti quando nel progetto sono presenti migliaia di oggetti diversi e centinaia di classi. Quindi le classi genitore (base) opportunamente selezionate consentono non solo di semplificare notevolmente la logica, ma anche di ridurre di dieci volte il codice.
3. Ereditarietà di classe —extends
Quindi cosa ci vuole per ereditare una classe? Affinché una classe ne erediti un'altra, devi scrivere la extends
parola chiave dopo la dichiarazione della classe figlia e quindi scrivere il nome della classe genitore. Di solito assomiglia a questo:
class Descendant extends Parent
Questo è ciò che devi scrivere quando dichiari la classe Descendant. A proposito, una classe può ereditare solo una classe.
Nella foto vediamo che una mucca ha ereditato un maiale, che ha ereditato una gallina, che ha ereditato un uovo. Un solo genitore! Tale eredità non è sempre logica. Ma quando tutto ciò che hai è un maiale e hai davvero bisogno di una mucca, i programmatori spesso non possono resistere all'impulso di trasformare un maiale in una mucca.
Java non ha ereditarietà multipla: una classe non può ereditare due classi. Ogni classe può avere una sola classe padre. Se non viene specificata alcuna classe genitore, la classe genitore è Object
.
Detto questo, Java ha un'ereditarietà multipla delle interfacce. Questo attenua leggermente il problema. Parleremo delle interfacce un po' più tardi, ma per ora continuiamo ad esplorare l'ereditarietà.