CIAO! Oggi daremo un'occhiata più da vicino a un principio della programmazione orientata agli oggetti (OOP): l'ereditarietà. Studieremo anche altri tipi di relazioni tra classi: composizione e aggregazione.
Questo argomento non sarà difficile: hai già incontrato eredità ed esempi di eredità molte volte nelle lezioni passate. Oggi, la cosa principale sarà rafforzare le tue conoscenze, esaminare più in dettaglio il meccanismo dell'ereditarietà e ancora una volta ripercorrere alcuni esempi. :) Bene, andiamo!
Quando abbiamo un paio di dozzine di classi di auto, la quantità di codice duplicato diventa davvero seria. Lo spostamento di campi e metodi comuni (chiamati anche "stati" e "comportamenti") in una classe genitore ci consente di risparmiare molto tempo e spazio. Se un tipo ha proprietà o metodi unici che altri tipi di auto non hanno, non è un grosso problema. Puoi sempre crearli in una classe discendente, separata da tutti gli altri.
Lo stesso vale per i campi: se una classe figlia ha proprietà uniche, dichiariamo tranquillamente questi campi all'interno della classe figlia e smettiamo di preoccuparci. :) La possibilità di riutilizzare il codice è il principale vantaggio dell'ereditarietà. Per i programmatori, è molto importante non scrivere codice extra. Ti imbatterai in questo ripetutamente nel tuo lavoro. Ricorda qualcos'altro di cruciale: Java non ha ereditarietà multipla. Ogni classe eredita solo una classe. Parleremo di più sulle ragioni di ciò nelle lezioni future. Per ora, ricordalo. A proposito, questo rende Java diverso da altri linguaggi OOP. Ad esempio, C++ supporta l'ereditarietà multipla. Tutto è più o meno chiaro con l'eredità. Andiamo avanti.

Ereditarietà in Java e suoi vantaggi
Come sicuramente ricorderai, l'ereditarietà è un meccanismo che ti consente di descrivere una nuova classe basata su una classe esistente (classe genitore). In tal modo, la nuova classe prende in prestito le proprietà e le funzionalità della classe genitore. Ricordiamo un esempio di eredità dato nelle lezioni precedenti:
public class Car {
private String model;
private int maxSpeed;
private int yearOfManufacture;
public Car(String model, int maxSpeed, int yearOfManufacture) {
this.model = model;
this.maxSpeed = maxSpeed;
this.yearOfManufacture = yearOfManufacture;
}
public void gas() {
// Gas
}
public void brake() {
// Brake
}
}
public class Truck extends Car {
public Truck(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
public class Sedan extends Car {
public Sedan(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
Abbiamo un certo programma che prevede il lavoro con vari tipi di auto. Anche se non sei un appassionato di auto, probabilmente sai che al mondo esistono moltissimi tipi di auto. :) Di conseguenza, separeremo le proprietà comuni delle auto in una classe genitore comune chiamata Car
. Quindi cosa è comune a tutte le auto, indipendentemente dal tipo? Ogni auto ha un anno di produzione, nome del modello e velocità massima. Inseriamo queste proprietà nei campi model
, maxSpeed
, e yearOfManufacture
. Per quanto riguarda il comportamento, qualsiasi macchina può accelerare e rallentare. :) Definiamo questo comportamento nella gas()
andbrake()
metodi. Quali vantaggi ci dà questo? Prima di tutto, riduce la quantità di codice. Naturalmente, possiamo fare a meno della classe genitore. Ma poiché ogni macchina deve essere in grado di accelerare e rallentare, dovremo creare metodi gas()
e brake()
nelle classi Truck
, Sedan
, F1Car
e SportsCar
e in ogni altra classe di auto. Immagina quanto codice extra dovremmo scrivere. E non dimenticare i campi model
, maxSpeed
, e yearOfManufacture
: se eliminiamo la classe genitore, dovremo crearli in ogni classe auto! 
public class F1Car extends Car {
public void pitStop() {
// Only race cars make pit stops
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
}
Diamo un'occhiata alle auto da corsa di Formula Uno come esempio. A differenza dei loro "parenti", hanno un comportamento unico: di tanto in tanto si fermano ai box. Questo non ci disturba. Abbiamo già descritto il comportamento comune nella Car
classe genitore e il comportamento specifico delle classi discendenti può essere aggiunto a quelle classi. 
Composizione e aggregazione
Classi e oggetti possono essere collegati tra loro. L'ereditarietà descrive una relazione "è-un". Un leone è un animale. Tale relazione è facilmente espressa usando l'ereditarietà, doveAnimal
è la classe genitore ed Lion
è il figlio. Tuttavia, non tutte le relazioni sono descritte in questo modo. Ad esempio, una tastiera è sicuramente correlata a un computer, ma non è un computer . Le mani sono in qualche modo legate a una persona, ma non sono una persona. In questi casi abbiamo un altro tipo di relazione: non "è-a", ma "ha-a". Una mano non è una persona, ma fa parte di una persona. Una tastiera non è un computer, ma fa parte di un computer. Una relazione has-a può essere descritta nel codice utilizzando la composizione e l'aggregazione. La differenza sta nella "rigorosità" del rapporto. Facciamo un semplice esempio: abbiamo una Car
classe. Ogni macchina ha un motore. Inoltre, ogni macchina ha passeggeri. Qual è la differenza fondamentale tra i campi Engine engine
e Passenger[] passengers
? Il fatto che il passeggero A
sia seduto in un'auto non significa che i passeggeri B
e C
non siano nell'auto. Un'auto può corrispondere a più passeggeri. Inoltre, se tutti i passeggeri scendono da un'auto, funzionerà comunque senza intoppi. La relazione tra la Car
classe e l' Passenger[] passengers
array è meno rigida. Si chiama aggregazione . Fornisce un altro buon esempio di aggregazione. Supponiamo di avere una Student
classe e aStudentGroup
classe. Uno studente può entrare a far parte di più organizzazioni studentesche: un club di fisica, un fan club di Star Wars e/o un comedy club studentesco. La composizione è un tipo di relazione più stretto. Quando si utilizza la composizione, un oggetto fa parte di un oggetto e non può appartenere a un altro oggetto dello stesso tipo. L'esempio più semplice è il motore di un'auto. Un motore fa parte di un'auto e non può far parte di un'altra auto. Come puoi vedere, la loro relazione è molto più stretta della relazione tra Car
e Passengers
. 
GO TO FULL VERSION