Alcuni Concetti Object-Oriented
Le proprietà principali della programmazione Object-Oriented
che hanno portato alla sua ampia diffusione, possono brevemente essere
riassunte come segue:
- chiarezza del codice;
- robustezza del codice;
- riusabilità del codice.
La chiarezza del codice è uno dei primi obiettivi ad essere stato raggiunto,
principalmente grazie all'introduzione di una fase di progettazione nell'ambito del
processo di produzione di codice. Ciò si realizza nella pratica tramite la
separazione ( in fase di design ) dei vari compiti su più oggetti, e
tramite l'incapsulamento dell'informazione ( INFORMATION HIDING )
all'interno degli oggetti, il che proibisce la stesura di codice con effetti
collaterali complessi e perciò difficili da capire e da modificare.
Anche la robustezza del codice, ovvero la capacità del sistema
software di evolvere nel tempo in seguito ai cambiamenti dell'ambiente, è
una conseguenza dell'importanza che la programmazione Object-Oriented
dà al design. La presenza di astrazioni potenti come le classi, consente di
focalizzare l'attenzione sulle interrelazioni fra le parti che logicamente costituiscono
il sistema. Ciò porta all'individuazione della struttura portante, per cui
modifiche graduali al modello difficilmente causeranno una riorganizzazione pervasiva
del sistema, piuttosto comporteranno la modifica di qualche componente del software
in questione.
Si osservi che le suddette caratteristiche sono tuttavia presenti,
seppure in minor grado, anche in altri paradigmi di programmazione.
Ciò che contraddistingue la programmazione Object-Oriented è
invece la riusabilità del codice, poiché sono presenti, allo scopo,
apposite tecniche implementative. Tipicamente diciamo che un componente software è
riusabile se può essere facilmente integrato in contesti diversi.
Per fare questo, è importante che l'oggetto sia bene progettato ( SELF-CONTAINED ),
ma anche che i vari contesti che lo devono accogliere abbiano un certo grado di recettività,
ovvero siano in grado di accogliere oggetti di tipo simile in maniera flessibile.
Si tratta pertanto di un meccanismo di sostituzione, che nei linguaggi Object-Oriented
può avere due forme diverse: sostituzione di oggetti con oggetti e
sostituzione di metodi con metodi.
La sostituzione fra oggetti si basa su un principio di polimorfismo detto
SUBSUMPTION: qualunque oggetto di una data classe X è
anche istanza della superclasse di X. Le ragioni a sostegno di tale principio
si fondano sul fatto che è intuitivo pensare, ad esempio, che una istanza
della classe RETTANGOLO possa essere sempre usata dove ci si aspetti
una qualunque figura geometrica poiché un rettangolo è una
figura geometrica.
La sostituzione fra metodi avviene nell'ambito dell'estensione di una classe
in una sottoclasse e prende il nome di OVERRIDING. Si tratta di un meccanismo
utile in quei casi in cui la sottoclasse necessita di ridefinire alcuni comportamenti
della superclasse in maniera più specifica.
La controparte dell'OVERRIDING, e cioè il riuso di un metodo
nella classe madre, è detto INHERITANCE.
Una conseguenza della presenza di questi mecanismi è che, a causa della
flessibilità nella sostituzione fra oggetti ( SUBSUMPTION ),
non è possibile stabilire a COMPILE-TIME il tipo
dell'oggetto che, ad un dato istante dell'esecuzione ( RUN-TIME ),
è legato ad una certa variabile.
Ciò porta alla necessità di distinguere fra un tipo statico e un
tipo dinamico della variabile:
- tipo statico, cioè il tipo con il quale la variabile viene
dichiarata nel codice. Si tratta della sola informazione di tipo nota a
COMPILE-TIME, sulla quale il codice che usa la variabile
può fare affidamento per stabilire a quali invocazioni di metodo l'oggetto
legato alla variabile può rispondere.
- tipo dinamico, ovvero il tipo dell'oggetto che in un certo istante
dell'esecuzione è legato alla variabile.
La rilevanza del concetto di tipo dinamico di un oggetto sta nel fatto che esso
è coinvolto nel cosiddetto DISPATCHING DINAMICO.
Il DISPATCHING DINAMICO consiste nello scegliere l'azione
che un certo oggetto esegue in risposta all'invocazione di un metodo, in base al
suo tipo dinamico piuttosto che al suo tipo statico. Ciò è necessario
perché, come conseguenza della SUBSUMPTION, un identificatore di
classe X, può in realtà contenere oggetti di qualunque
sottoclasse di X, la quale possibilmente ridefinisce ( OVERRIDE )
il metodo che si sta invocando, ed è quindi più corretto che sia questo
nuovo metodo ad essere eseguito, piuttosto che quello definito da X.
Il DISPATCHING DINAMICO è presente in tutti i linguaggi
Object-Oriented, al punto da poterlo pensare come una caratteristica
essenziale di tale paradigma.
Da un punto di vista concettuale, l'importanza del DISPATCHING DINAMICO
sta nel fatto che consente di pensare agli oggetti come delle unità autonome,
capaci di comportamento proprio, indipendente dal contesto statico in cui vengono utilizzate.