6 - Unità didattica
5.6)
Elenco delle pagine di "Il
linguaggio Java: lez.6"
Introduzione e Unità didattica 5.1) - Pagina 1
Introduzione e Unità didattica 5.2) - Pagina 2
Unità didattica 5.3) - Pagina 3
Unità didattica 5.4) - Pagina 4
Unità didattica 5.5) - Pagina 5
Unità didattica 5.6) - Pagina 6
- Quando utilizzare
l’ereditarietà
Quando si parla di ereditarietà, si è spesso convinti che per
implementarla basti avere qualche classe che dichiari campi in
comune. In realtà ciò potrebbe essere interpretato come un primo
passo verso un’eventuale implementazione di ereditarietà. Il test
decisivo deve però essere fatto mediante la cosiddetta "is a"
relationship (la relazione "è un").
- La relazione "is a":
Per un corretto uso dell’ereditarietà, il programmatore dovrà porsi
una fondamentale domanda: un oggetto della candidata sottoclasse "è
un" oggetto della candidata superclasse? Se la risposta alla domanda
è negativa, l’ereditarietà non si deve utilizzare. Effettivamente,
se l’applicazione dell’ereditarietà, dipendesse solamente dai campi
in comune tra due classi, potremmo trovare relazioni d’estensione
tra classi quali:
class Triangolo
{
public final int numeroLati=3;
public float lunghezzaLatoUno;
public float lunghezzaLatoDue;
public float lunghezzaLatoTre;
. . . . . . . .
}
class Rettangolo extends Triangolo
{
public final int numeroLati=4;
public float lunghezzaLatoQuattro;
. . . . . . . .
}
ma ovviamente un rettangolo non è
un triangolo e per la "is a" relationship questa estensione non è
valida. La nostra esperienza ci dice che se iniziassimo un progetto incrementale, senza utilizzare questo test, potremmo
arrivare ad un punto dove la soluzione migliore per continuare sia
quella di ricominciare da capo!
N.B.: siccome tutto è un oggetto, tutte le classi estenderanno
Object.
- Generalizzazione e Specializzazione:
Sono due termini che definiscono i processi che portano
all’implementazione dell’ereditarietà.
Si parla di generalizzazione, se a partire da un certo numero di
classi, si definisce una superclasse che raccoglie le
caratteristiche comuni. Viceversa si parla di specializzazione
quando, partendo da una classe, si definiscono una o più
sottoclassi, allo scopo di ottenere oggetti più specializzati.
Nell’ultimo esempio avevamo a disposizione la classe Triangolo e la
classe Rettangolo. Abbiamo notato come il test "is a" fallendo ci
"sconsigli" l’implementazione dell’ereditarietà. Eppure queste due
classi hanno qualcosa in comune: si possono considerare entrambi
poligoni. La soluzione quindi sembra consistere nel generalizzare in
una classe che potremmo chiamare proprio Poligono, che potrebbe
essere estesa dalle classi Triangolo e Rettangolo, nel modo
seguente:
class Poligono
{
public int numeroLati;
public float lunghezzaLatoUno;
public float lunghezzaLatoDue;
public float lunghezzaLatoTre;
. . . . . . . .
}
class Triangolo extends Poligono
{
public final int numeroLati=3;
. . . . . . . .
}
class Rettangolo extends Poligono { public final
int numeroLati=4; public float lunghezzaLatoQuattro; . . . . . . . .
}
Se fossimo partiti dalla classe Poligono per definire le due
sottoclassi, avremmo parlato invece di specializzazione.
- Rapporto ereditarietà -
incapsulamento:
Dal momento che l’incapsulamento si può considerare obbligatorio, e
l’ereditarietà, un prezioso strumento di programmazione, bisognerà
chiedersi cosa provocherà, l’utilizzo combinato di entrambi i
paradigmi. Ovvero: cosa erediteremo da una classe incapsulata?
Abbiamo già affermato che estendere una classe significa ereditarne
i membri non privati. E’ quindi escluso che, in una nuova classe
Ricorrenza ottenuta specializzando la classe Data definita
precedentemente, si possa accedere alle variabili giorno, mese e
anno, direttamente, giacché queste, non saranno ereditate. Ma,
essendo tutti i metodi d’accesso alle variabili dichiarati pubblici
nella superclasse, saranno ereditati e quindi utilizzabili nella
sottoclasse. Concludendo, anche se la classe Ricorrenza non possiede
esplicitamente le variabili private di Data, può comunque usufruirne
tramite l’incapsulamento. In pratica le possiede virtualmente.
- Modificatore protected:
Oltre ai modificatori private e public, esiste un terzo
specificatore d’accesso: protected. Un membro dichiarato protetto,
sarà accessibile solo dalle classi appartenenti allo stesso package
in cui è dichiarato, e può essere ereditato da sottoclassi
appartenenti a package differenti. I package e tutti gli
specificatori d’accesso saranno argomento del settimo capitolo.
- Conclusioni:
Le conclusioni che potremmo trarre dall’argomento ereditarietà sono
ormai chiare ma non finali. Il concetto di ereditarietà ci ha aperto
una strada con tante diramazioni, la strada della programmazione ad
oggetti. Dalla definizione dell’ereditarietà nascono fondamentali
concetti quali quelli del polimorfismo, nuovi potenti parole chiave
come "super", e ci saranno nuove situazioni di programmazione da
dover gestire correttamente. Dal prossimo modulo in poi, quindi, ci
caleremo nel supporto che Java offre alla programmazione ad oggetti
e nelle caratteristiche avanzate del linguaggi.
Elenco delle pagine di "Il linguaggio Java: lez.6"
Introduzione e Unità didattica 5.1) - Pagina 1
Introduzione e Unità didattica 5.2) - Pagina 2
Unità didattica 5.3) - Pagina 3
Unità didattica 5.4) - Pagina 4
Unità didattica 5.5) - Pagina 5
Unità didattica 5.6) - Pagina 6