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