Prev   Top   Next 

Introduzione

Lo scopo di queste pagine è l'analisi di una architettura astratta adatta all'esecuzione di programmi Object-Oriented, sulla falsariga di Java. Prima di presentare l'architettura vengono brevemente riassunte quelle caratteristiche di Object-Orientation che sono incorporate nell'architettura della Macchina Astratta.

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.

La Macchina Astratta che analizzeremo nel seguito è pensata per supportare alcune delle caratteristiche dei linguaggi Object-Oriented sopra esposte, fra cui principalmente il DISPATCHING DINAMICO. La sua architettura è basata sulla JVM ( Java Virtual Machine ), ma alcuni aspetti sono stati semplificati per una maggiore chiarezza espositiva.

 Prev   Top   Next