Per implementare le operazioni, procedere nel seguente modo:
-
Scegliere un algoritmo.
-
Scegliere le strutture di dati appropriate agli algoritmi.
-
Definire le nuove classi e operazioni secondo necessità.
-
Creare il codice dell'operazione.
Scegliere un algoritmo
Molte operazioni sono semplici abbastanza per essere implementate dall'operazione e la relativa specifica.
Gli algoritmi non banali sono necessari principalmente per due motivi: per implementare le operazioni complesse per cui
viene fornita una specifica e per ottimizzare le operazioni per cui viene utilizzato un semplice ma inefficace
algoritmo.
Scegliere le strutture di dati appropriate agli algoritmi
La scelta degli algoritmi coinvolge la scelta della struttura di dati su cui agiscono. Molte implementazioni di
strutture di dati sono classi di contenitore, come matrici, liste, code, pile, insiemi, bag e relative variazioni. La
maggior parte dei linguaggi orientati agli oggetti e gli ambienti di programmazione forniscono librerie di classe con
questi tipi di componenti riutilizzabili.
Definire le nuove classi e operazioni secondo necessità
Le nuove classi possono essere istituite per conservare risultati intermedi, ad esempio. È possibile aggiungere alla
classe nuove operazioni di basso livello per decomporre un'operazione complessa. Tali operazioni sono spesso riservate
alla classe, cioè non visibili all'esterno della stessa classe.
Creare il codice dell'operazione
Scrivere il codice per l'operazione iniziando con la relativa dichiarazione di interfaccia. Seguire le linee guida di
programmazione applicabili.
Lo stato di un oggetto può essere implementato attraverso il riferimento ai valori dei suoi attributi, senza alcuna
rappresentazione speciale. Le transizioni di stato per tale oggetto saranno implicite nel cambiamento dei valori degli
attributi e i comportamenti variabili vengono programmati attraverso dichiarazioni condizionali. Tale soluzione
non è soddisfacente per il comportamento complesso poiché porta solitamente a strutture complesse difficili da
modificare quando vengono aggiunti più stati o il comportamento cambia.
Se il comportamento dell'elemento di progettazione (o i relativi costituenti) dipende dallo stato, ci saranno di solito
uno o più diagrammi di stato che descrivono il comportamento degli elementi di modello nell'elemento di progettazione.
Tali diagrammi vengono utilizzati come input importante durante l'implementazione.
Le macchine a stati mostrate nei diagrammi di stato rendono esplicito lo stato di un oggetto e le transizioni e il
comportamento richiesto vengono delineati in modo chiaro. Una macchina a stati può essere implementata nei seguenti
modi:
-
Le macchine a stati semplici possono essere implementate definendo un attributo che elenca i possibili stati e
utilizzando l'attributo per selezionare il comportamento per i messaggi in arrivo. Ad esempio, in una istruzione
switch in Java o C++. Questa soluzione non si adatta molto bene alle macchine a stati complesse e può portare a
ridotte prestazioni di esecuzione. Consultare [DOUG98], capitolo
4, 4.4.3 per un esempio di questo metodo
-
Le macchine a stati più complesse possono utilizzare il pattern di stato. Consultare [GAM94] per una descrizione del pattern di stato. [DOUG98], capitolo 6, 6.2.3, Pattern di stato, descrive anche questo
approccio
-
Un approccio gestito da tabelle funziona meglio per le macchine a stati molto complesse dove la facilità di
modifica è un criterio. In questo approccio, sono presenti voci per ogni stato in una tabella dove la voce associa
gli input agli stati che si succedono e alle azioni di transizione associate. Consultare [DOUG98], capitolo 6, 6.2.3, Pattern di tabella di stato, per un esempio di
questo metodo.
Le macchine a stati con stati secondari simultanei possono essere implementate delegando la gestione dello stato agli
oggetti attivi, uno per ogni stato simultaneo, perché gli stati simultanei rappresentano calcoli indipendenti (che
possono, tuttavia, interagire). Ogni stato secondario può essere gestito utilizzando una delle tecniche descritte in
precedenza.
Se è possibile implementare una classe o parti di essa utilizzando una classe esistente, utilizzare la delega piuttosto
che l'eredità.
Per delega si intende l'implementazione della classe con l'aiuto di altre classi. La classe fa riferimento a un oggetto
dell'altra classe utilizzando una variabile. Quando un'operazione viene chiamata, si chiama un'operazione nell'oggetto
riferito (della classe riutilizzata) per l'esecuzione attuale. In tal modo, delega la responsabilità all'altra classe.
Un'associazione a una via viene implementata come puntatore, un attributo che contiene un riferimento di oggetto. Se la
molteplicità è uno, viene implementata come un semplice puntatore. Se la molteplicità è molti, viene
implementata come insieme di puntatori. Se la molteplicità molti è ordinata, è possibile utilizzare un elenco al
posto di un insieme.
Un'associazione a due vie viene implementata come attributi in entrambe le direzioni, utilizzando tecniche per
associazioni a una via.
Un'associazione qualificata viene implementata come una tabella di ricerca (ad esempio, una classe Smalltalk
Dictionary) nell'oggetto qualificante. I valori del selettore nella tabella di ricerca sono i qualificatori e i valori
di destinazione sono gli oggetti dell'altra classe.
Se è necessario accedere ai valori del qualificatore in ordine, i qualificatori possono essere organizzati in una
matrice o in una struttura ad albero ordinata. In questo caso il tempo di accesso sarà proporzionale a log N dove N è
il numero dei valori del qualificatore.
Se i qualificatori vengono presi da un insieme limitato compatto, i valori del qualificatore possono essere mappati in
un intervallo di interi e l'associazione può essere implementata in modo efficiente come una matrice. Questo approccio
è più attraente se l'associazione è popolata prevalentemente completa piuttosto che in modo sparso ed è ideale per gli
insiemi limitati completamente popolati.
La maggior parte dei linguaggi orientati agli oggetti e gli ambienti di programmazione forniscono librerie di classe
con componenti riutilizzabili per implementare diversi tipi di associazioni.
Gli attributi vengono implementati in uno dei tre modi seguenti: utilizzando tipi primitivi incorporati, utilizzando
una classe esistente o definendo una nuova classe. La definizione di una nuova classe è spesso più flessibile, ma
introduce azioni indirette non necessarie. Ad esempio, un numero di previdenza sociale di un impiegato può essere
implementato con attributo di tipo String o come nuova classe.
Implementazioni alternative di un attributo.
Può accadere che gruppi di attributi vengano combinati in nuove classi, come mostra il seguente esempio. Entrambe le
implementazioni sono corrette.
Gli attributi in Linea vengono implementati come associazioni a una classe Point.
|