Un meccanismo di progettazione è il perfezionamento di un corrispondente meccanismo di analisi(consultare anche Concetto:
Meccanismi di analisi). Un meccanismo di progettazione aggiunge dettagli concreti al meccanismo di analisi
concettuale ma evita la richiesta di tecnologia particolare - ad esempio, un'implementazione particolare di un
fornitore relativa ad un sistema di gestione database orientato sugli oggetti. Come per i meccanismi di analisi, un
meccanismo di progettazione può creare istanze di uno o più pattern, in questo caso pattern strutturali o di
progettazione.
In modo simile, un meccanismo di implementazione è un perfezionamento di un corrispondente meccanismo
di progettazione, che utilizza, ad esempio, un linguaggio di programmazione particolare e diversa tecnologia di
implementazione (ad esempio un particolare prodotto middleware del fornitore). Un meccanismo di implementazione può
creare l'istanza di uno o più idiomi o
pattern di implementazione.
Si prenda in considerazione il meccanismo di analisi di Persistenza:
-
Potrebbe essere necessario memorizzare per alcuni secondi molti (2.000) oggetti piccoli (200 byte ognuno), senza
bisogno che sopravvivano.
-
Potrebbe essere necessario memorizzare permanentemente alcuni oggetti molto grandi sul disco per diversi mesi, mai
aggiornati ma con sofisticati mezzi di richiamo.
Questi oggetti richiederanno un supporto di persistenza diverso; potrebbero
essere identificate le seguenti caratteristiche di meccanismi di progettazione per il supporto di persistenza:
-
Memorizzazione In-memory; caratteristiche: per un massimo di 1 Mb totale (dimensione x volume); accesso
molto veloce per lettura, scrittura, aggiornamento.
-
Flash card; caratteristiche: fino a 8 Mb; accesso lento per aggiornamento e scrittura; accesso moderato per
la lettura.
-
File binario; caratteristiche: da 100 Kb a 200 Mb; aggiornamento lento; accesso lento per lettura e
scrittura.
-
Database Management System (DBMS); caratteristiche: da 100 Kb a salire (essenzialmente senza limite
massimo); aggiornamento, lettura e scrittura ancora più lenti.
Queste velocità sono giudicate 'lente' in relazione alla memorizzazione di tipo in-memory. Ovviamente, in alcuni
ambienti, l'utilizzo della cache può migliorare i tempi di accesso apparenti.
Inizialmente, la mappatura fra i meccanismi di progettazione e quelli di implementazione è probabilmente meno che
ottimale ma sufficiente ad eseguire il progetto, identificare i rischi non ancora rilevati ed attivare ulteriori
indagini e valutazioni. Col proseguire del progetto e l'aumentare della conoscenza, la mappatura deve essere
perfezionata.
Procedere iterativamente per perfezionare la mappatura fra i meccanismi di progettazione e di implementazione,
eliminando i percorsi ridondanti, lavorando sia dall'alto verso il basso che viceversa.
Lavorare dall'alto verso il basso Quando si lavora "dall'alto verso il basso", nuove realizzazioni perfezionate
di casi d'uso collocano dei nuovi requisiti sui necessari meccanismi di progettazione tramite i meccanismi di analisi
necessari. I nuovi requisiti potrebbero mettere a nudo ulteriori caratteristiche di un meccanismo di progettazione,
forzando una separazione fra i meccanismi. Esiste anche un compromesso fra la complessità del sistema e le sue
prestazioni:
-
Troppi meccanismi di progettazione diversi rendono il sistema troppo complesso.
-
Pochi meccanismi di progettazione possono creare delle problematiche di prestazione ad alcuni meccanismi di
implementazione che allungano i limiti degli intervalli ragionevoli dei relativi valori delle caratteristiche.
Lavorare dal basso verso l'alto. Quando si lavora "dal basso verso l'alto", indagando sui meccanismi di
implementazione disponibili, è possibile trovare dei prodotti che soddisfano immediatamente diversi meccanismi di
progettazione, ma forzano un certo adattamento o una ripartizione del meccanismo di progettazione. Si desidera ridurre
al minimo il numero di meccanismi di implementazione utilizzati ma anche il fatto che siano troppo pochi può portare a
problematiche di prestazione.
Una volta deciso di utilizzare un DBMS per memorizzare gli oggetti di classe A, si potrebbe essere tentati
dall'utilizzarlo per memorizzare tutti gli oggetti del sistema. Questo potrebbe rivelarsi molto inefficiente, o molto
scomodo. Non tutti gli oggetti che richiedono persistenza devono essere memorizzato nel DBMS. Alcuni oggetti possono
essere permanenti ma potrebbero essere acceduti spesso dall'applicazione e solo raramente acceduti da altre
applicazioni. Il migliore approccio potrebbe essere una strategia ibrida, in cui l'oggetto viene letto dal DBMS nella
memoria e sincronizzato periodicamente.
Esempio
Un volo potrebbe essere memorizzato in memoria per un accesso rapido, e in un DBMS per una persistenza a lungo termine;
questo, tuttavia, attiva per il meccanismo l'esigenza di dover sincronizzare entrambi.
Non è inusuale disporre di più di un meccanismo di progettazione associato ad una classe client come compromesso fra le
differenti caratteristiche.
Poiché i meccanismi di implementazione spesso sono forniti in gruppi nei componenti già pronti (sistemi operativi e
prodotti middleware) devono essere eseguite alcune ottimizzazioni in base ai costi o a mancata corrispondenza di
impedenza o uniformità di stile. Inoltre i meccanismi spesso sono interdipendenti, cosa che rende difficile una netta
separazione dei servizi nei meccanismi di progettazione.
Esempi
Il perfezionamento continua nell'intera fase di elaborazione ed è sempre un compromesso fra:
-
Un'esatta 'corrispondenza' con i requisiti dei client del meccanismo di progettazione, in termini di
caratteristiche previste.
-
Il costo e la complessità di avere troppi meccanismi di implementazione da acquisire ed integrare.
L'obiettivo generale è sempre di avere un insieme semplice pulito di meccanismi che forniscono ad un sistema di grandi
dimensioni integrità concettuale, semplicità ed eleganza.
I meccanismi di progettazione Persistenza possono essere messi in corrispondenza con i meccanismi di
implementazione nel modo seguente:
Una possibile mappatura fra i meccanismi di analisi e i meccanismi di progettazione. Le frecce tratteggiate significano
"viene specializzato da", implicando che le caratteristiche dei meccanismi di progettazione vengono ereditati dai
meccanismi di analisi ma che verranno specializzati e perfezionati.
Una volta terminata l'ottimizzazione dei meccanismi, esistono le seguenti mappature:
Le decisioni di progettazione per una classe client in termini di mappature fra i meccanismi; la classe Flight
necessita di due forme di persistenza: memorizzazione in-memory implementata da una routine di libreria già pronta,
e in un database implementato con un prodotto ObjectStorage acquistabile.
La mappa deve essere esplorabile in entrambe le direzioni, in modo che sia facile individuare le classi client quando
si cambiano i meccanismi di implementazione.
I meccanismi di progettazione e i dettagli relativi al loro utilizzo sono documentati nel Prodotto di lavoro: Linee guida specifiche per progetto. La relazione
(o mappatura) fra i meccanismi di analisi, quelli di progettazione, quelli di implementazione ed il fondamento logico
associato alle scelte, è documentata nel Prodotto di lavoro: Documento dell'architettura software.
Come per i meccanismi di analisi, i meccanismi di progettazione possono essere modellati utilizzando una
collaborazione, che può creare istanze di uno o più pattern strutturalio di
progettazione.
Esempio: un meccanismo di persistenza
Questo esempio utilizza l'istanza di un pattern per una persistenza basata su RDBMS preso da JDBC™ (Java Data Base Connectivity).
Anche se qui viene presentata la progettazione, JDBC fornisce il codice effettivo per alcune delle classi, quindi il
passo da quello che viene presentato qui ad un meccanismo di implementazione, è breve.
La figura Vista statica: JDBC mostra le classi (esattamente, i ruoli del classificatore) nella collaborazione.
Vista statica: JDBC
Le classi gialle sono quelle che sono state fornite, le altre (myDBClass ecc.) sono state collegate dal progettista per
creare il meccanismo.
In JDBC, un client utilizzerà una DBClass per la lettura e la scrittura di dati permanenti. La DBClass è
responsabile dell'accesso al database JDBC tramite la classe DriverManager. Una volta aperta una
Connessione al database, la DBClass può creare istruzioni SQL che verranno inviate al RDBMS sottostante ed
eseguita utilizzando la classe Statement. La classe Statement è quella che "dialoga" con il database. Il
risultato della query SQL viene restituito in un oggetto ResultSet.
La classe DBClass deve rendere permanente un'altra istanza di classe. Comprende la mappatura da-OO-a-RDBMS ed ha
la funzionalità di interfaccia con RDBMS. La DBClass appiattisce l'oggetto, lo scrive in RDBMS, legge i dati
dell'oggetto da RDBMS e crea l'oggetto. Ogni classe permanente avrà una
DBClass corrispondente.
PersistentClassList viene utilizzato per restituire un insieme di oggetti permanenti come risultato di una query
del database (ad es., DBClass.read()).
Ora viene presentata una serie di viste dinamiche per mostrare come funziona effettivamente il meccanismo.
JDBC: Inizializzazione
L'inizializzazione deve verificarsi prima di poter accedere a qualunque classe permanente.
Per inizializzare la connessione al database, DBClass deve caricare il driver appropriato richiamando l'operazione
DriverManager getConnection() con URL, utente e password.
L'operazione getConnection() tenta di stabilire una connessione all'URL di database fornito. DriverManager tenta di
selezionare un driver appropriato dalla serie di driver JDBC registrati.
Parametri:
url: un url di database nel formato jdbc:subprotocol:subname. Questo URL viene utilizzato per individuare il
server di database effettivo e in questa istanza non è correlato a Web.
utente: l'utente del database per conto del quale è stata effettuata la connessione
pass: la password dell'utente
Restituisce:
una connessione all'URL.
JDBC: Creazione
Per creare una nuova classe, il client di persistenza chiede alla DBClass di crearla. La DBClass crea una nuova istanza
di PersistentClass con i valori predefiniti. La DBClass quindi crea una nuova istruzione utilizzando l'operazione
createStatement() della classe Connectiion. L'istruzione viene eseguita e i dati vengono inseriti nel database.
JDBC: Lettura
Per leggere una classe permanente, il client di persistenza chiede alla DBClass di leggere. La DBClass crea una nuova
istruzione utilizzando l'operazione createStatement() della classe Connection. L'istruzione viene eseguita ed i dati
vengono restituiti in un oggetto ResultSet. La DBClass quindi crea una nuova istanza di PersistentClass e la popola con
i dati richiamati. I dati vengono restituiti in un oggetto di raccolta, un'istanza della classe PersistentClassList.
Nota: la stringa passata a executeQuery() non è necessariamente esattamente la stessa passata nell'operazione read().
DBClass crea la query SQL per richiamare i dati permanenti dal database, utilizzando i criteri passati nell'operazione
read(). Questo avviene perché il client di DBClass non debba dover conoscere l'interno del database per creare una
query valida. Questa conoscenza è incapsulata all'interno della DBClass.
JDBC: Aggiornamento
Per aggiornare una classe, il client di persistenza chiede a DBClass di aggiornare. DBClass richiama i dati
dall'oggetto PersistentClass fornito crea una nuova istruzione utilizzando l'operazione createStatement() della classe
Connection. Una volta creata l'istruzione, viene eseguito l'aggiornamento ed il database viene aggiornato con i nuovi
dati provenienti dalla classe.
Attenzione: è compito della DBClass "appiattire" la PersistentClass e scriverla nel database. Questo è il motivo per
cui deve essere richiamata dalla PersistentClass specificata, prima di poter creare l'istruzione SQL.
Nota: nel meccanismo appena descritto, PersistentClass deve fornire le routine di accesso per tutti i dati permanenti
perché DBClass possa accedervi. Questo fornisce l'accesso esterno a determinati attributi permanenti che altrimenti
sarebbero stati privati. Questo è il prezzo da pagare per estrarre la conoscenza della persistenza dalla classe che
incapsula i dati.
JDBC: Eliminazione
Per eliminare una classe, il client di persistenza chiede a DBClass di eliminare PersistentClass. La DBClass crea una
nuova istruzione utilizzando l'operazione createStatement() della classe Connection. L'istruzione viene eseguita e i
dati vengono rimossi dal database.
Nell'implementazione di questa progettazione, verrebbero prese alcune decisioni relative alla mappatura di DBClass con
le classi permanenti, ad es. disponendo una DBClass per classe permanente ed assegnandole ai pacchetti appropriati.
Questi pacchetti avranno una dipendenza sul pacchetto java.sql fornito (consultare JDBC™
Documentazione API) che contiene le classi di supporto DriverManager, Connection, Statement e ResultSet.
|