In informatica l'ereditarietà è
uno dei concetti fondamentali nel paradigma di programmazione a oggetti. In
generale, essa rappresenta un meccanismo che consente di creare nuovi oggetti
che siano basati su altri già definiti.
Si definisce oggetto figlio (child object)
quello che eredita tutte o parte delle proprietà e dei metodi definiti nell’oggetto
padre (parent object).
Essa consiste in una relazione che il linguaggio di programmazione, o il programmatore stesso,
stabilisce tra due classi. Se la classe B eredita
dalla classe A, si dice che B è una sottoclasse di A e
che A è una superclasse di B.
A seconda del linguaggio di programmazione, l'ereditarietà può essere ereditarietà
singola o semplice (ogni
classe può avere al più una superclasse diretta) o multipla (ogni classe può
avere più superclassi dirette).
In generale, l'uso dell'ereditarietà dà luogo a una
gerarchia di classi; nei linguaggi con ereditarietà singola, si ha un albero se
esiste una superclasse "radice" unica di cui tutte le altre sono
direttamente o indirettamente sottoclassi o a una foresta altrimenti;
l'ereditarietà multipla definisce invece una gerarchia a grafo aciclico diretto.
Un esempio che metta in luce la potenza dell’ereditarietà,
in un programma Windows object oriented potrebbe avere come oggetto fulcro le
finestre associate al programma stesso. Supponiamo, ad esempio, che tale
software utilizzi, in totale, 100 finestre differenti, visualizzabili a secondo
del contesto in cui sta navigando l’utente.
Se, un giorno, si volesse inserire un campo comune a tutte
le finestre del programma, in che modo sarà bene procedere? Se non avessimo
utilizzato la potenza dell’ereditarietà l’unica strada percorribile sarebbe
quella di andarsi a prendere una per una tutte le definizioni delle finestre e
inserire il nuovo campo.
Se, invece, si fosse utilizzato in maniera efficiente il
paradigma Object Oriented, definendo una classe FinestraBase contenente tutte
le caratteristiche comuni ad ogni finestra e derivando da tale classe tutte le
finestre in gioco nel programma, allora la modifica sarebbe banalmente quella di inserire il nuovo campo nella
classe FinestraBase. Graficamente:
L'ereditarietà è una relazione di
generalizzazione/specificazione: la superclasse definisce un concetto generale
e la sottoclasse rappresenta una variante specifica di tale concetto generale.
Su questa interpretazione si basa tutta la teoria dell'ereditarietà nei
linguaggi a oggetti. Oltre a essere un importante strumento di modellazione,
l'ereditarietà ha importantissime ripercussioni sulla riusabilità del
software.
Per esempio, data una classe telefono se ne
potrebbe derivare la sottoclasse cellulare, poiché il cellulare è un caso particolare di telefono.
Questo tipo di relazione viene detta anche relazione is-a ("è-un"):
"un cellulare è-un telefono".
Gli oggetti appartenenti a una sottoclasse devono essere in
grado di esibire tutti i comportamenti e le proprietà esibiti da quelli
appartenenti alla superclasse, in modo tale che usarli in luogo di questi
ultimi non alteri la correttezza delle informazioni restituite dal programma. È
importante, però chiarire un aspetto importante quando si parla di
caratteristiche ereditate. Non sempre, infatti, un determinato metodo definito
nella classe padre può produrre risultati corretti e congruenti con tutte le
classi figlie.
Ad esempio, supponiamo di aver definito una classe padre
denominata Uccello, dalla quale faremo derivare le seguenti classi figlie:
Passerotto, Merlo e Pinguino.
Nella classe padre, avremo definito il metodo vola(), in
quanto rappresenta un comportamento comune a tutti gli uccelli. In tal modo,
secondo quanto si è detto in questo paragrafo, tutte le classi figlie non
avranno la necessità di implementare tale metodo ma lo erediteranno dalla
classe Uccello. Purtroppo, però, nonostante il pinguino appartenga alla
categoria degli uccelli, è noto che esso non è in grado di volare, seppur
provvisto di ali.
In questo caso, il metodo vola() definito nella classe
Uccello, sicuramente valido per la stragrande maggioranza di uccelli, non sarà
utile (anzi, sarà proprio sbagliato) per la classe Pinguino. Come comportarsi
in questi casi?
Ogni oggetto derivante da una classe padre ha la possibilità
di ignorare uno o più metodi in essa definiti riscrivendo tali metodi al suo
interno. Questa caratteristica è nota come overriding.
Utilizzando la tecnica dell’overriding, la classe Pinguino
reimplementerà al suo interno il metodo vola(), conservando, comunque, la
possibilità di richiamare in qualunque momento, anche il metodo definito nella
classe padre. In quest’ultimo caso si parlerà di overriding parziale.
Esempio:
Esempio:
Public Class Impiegato private nome as String private salario as Double private matricola as String private anniDiServizio as Integer Public Sub New(n As String, s as Double, m as String, ads as Integer) nome = n salario = s matricola = m anniDiServizio = ads End Sub Public Sub incrementaSalario(double percentuale) salario *= 1 + percentuale / 100 End Sub Public Sub stampaInfo() System.Console.WriteLine (nome + " " + salario + " " + matricola) End Sub Public ReadOnly Property Nome as String Get return nome End Get End Property Public AnniServizio as Integer Get return anniDiServizio End Get End Property End Class Public Class Manager Inherits Impiegato Private nomeSegretaria as String Public Sub New(n as String, s as Double, m asString, ads as Integer) MyBase.New(n, s, m, ads) nomeSegretaria = String.empty End Sub Public Sub incrementaSalario(percentuale as Double) ' Aggiunge alla percentuale lo 0.5% per ogni anno di servizio Dim bonus as Double = 0.5 * AnniServizio MyBase.incrementaSalario(percentuale + bonus) End Sub Public Property Segretaria as String Get return nomeSegretaria End Get Set(ByValue Value as String) nomeSegretaria = Value End Set End Property End Class
Nessun commento:
Posta un commento