Andiamo adesso ad analizzare un altro strumento molto potente che ci mette a disposizione la programmazione ad oggetti ovvero l’eriditarietà.
Utilizzando questo strumento potremo ereditare codice scritto in una classe ed ampliarlo, ottenendo così un’estensione della classe dalla quale abbiamo eriditato il codice. Facciamo subito un esempio per comprendere al meglio il concetto esposto precedentemente:
public class Dipendente {
public String nome;
public String cognome;
public int stipendio;
}
Immaginiamo adesso di voler creare una classe per i dependenti che però sono responsabili di un progetto. Avremo che gli attributi della classe "Dipendete" saranno comuni sia alla figura del dipendente che a quella del responsabile di progetto, ma quest’ultimo avrà un ulteriore attributo che indica il progetto di cui è responsabile. La cosa migliore da fare è, dunque, estendere la classe "Dipendente" utilizzando la parola chiave extends:
public class DipendenteResponsabile extends Dipendente {
public String progetto;
}
A questo punto avremo una classe "DipendenteResponsabile" che conterrà l’attributo "progetto" più gli atri attributi eriditati dalla classe "Dipendente".
Per capire meglio i vantaggi dell’ereditarietà facciamo un piccolo esempio. Immaginiamo che all’interno dell’azienda siano presenti le seguenti figure: il dipendente, il responsabile di progetto, il responsabile di settore ed il direttore. Immaginiamo di non usare l’ereditarietà nello sviluppo della nostra applicazione, quindi dovremo creare quattro classi distinte che hanno però molti attributi in comune. Scritte queste classi, immaginiamo che dopo qualche tempo vogliamo registrare anche la data di nascita di ogni dipendente della ditta e il giorno in cui è stato assunto. Nel nostro caso dovremo andare a mettere mano ad ogni singola classe prima creata aggiungendo gli attributi. Utilizzando l’ereditarietà questa modifica risulterebbe veramente banale in quando avremo una classe "Dipendente" e altre tre classi che la estendono per il responsabile di progetto, di settore e il direttore. In Questo modo basterà modificare esclusivamente la classe "Dipendente" ed otterremo il risultato voluto senza toccare le classi che ne sono l’estensione. Sicuramente su progetti di grosse dimensioni questo è più che un grosso vantaggio.
Quando estendiamo una classe, però, non vengono ereditati tutti gli attributi della classe e tutti i metodi ma bensì solo quelli dichiarati public. Quindi utilizzando l’incapsulamento degli attributi della classe dichiarandoli come privati, quest’ultimi non verranno direttamente eriditati. Però, negli esempi precedenti, i metodi che si occupano della manipolazioni degli attributi sono stati dichiarati come pubblici e quindi verranno correttamente ereditati. Automaticamente, ereditando i metodi che gestiscono gli attributi, avremo modo di accedere agli attributi stessi e quindi incapsulamento ed ereditarietà possono convivere senza nessun problema.
L’ereditarietà può essere usuta sempre e, di fatto, ogni classe può essere estesa. Esiste però un corretto utilizzo dell’ereditarietà che si rifà alla logica implementativa. Dunque, prima di ereditare una classe dovremo sempre chiederci se ciò che stiamo facendo ha una logica oppure no. Immaginiamo di avere la nostra classe "Dipendete" avente solo due attributi (nome e cognome) e di creare un’altra classe "Fornitore" che oltre al nome e al cognome ha un attributo "prezzo" che indica il valore dell’ultimo ordine effettuato. Si potrebbe essere tentati, a questo punto, di estendere la classe "Dipendente" e aggiungere il solo attributo prezzo, ma questo, se dal punto di vista della programmazione non da nessun errore, dal punto di vista logico è evidentemente errato in quando un fornitore non è un dipendente. Questo esempio per dire che è buona norma ereditare una classe se si risponde in maniera affermativa alla domanda … è un …?":
- un fornitore è un dipendente? No, quindi non estendo la classe "Dipendente" e creerò una classe fornitore a parte.
- il resposabile pubblicitario dell’azienda è un dipendente? Si, quindi estenderò la classe "Dipendente" magari aggiungendo l’attributo che indica il budget pubblicitario mensile affidatogli.
In java tutte le volte che creiamo una classe (senza eridatarietà) è come se ereditassimo la classe Object che il Java ci mette a disposizione. Infatti se scrivessimo il seguente codice:
public class Dipendente extends Object {
}
non otterremo nessun errore di compilazione in quanto, in caso di assenza della parte extends Object questa viene aggiunta all’atto della compilazione.