Operazione: Progettazione caso d'uso
Questo compito illustra come perfezionare i prodotti dell'analisi del caso d'uso sviluppando delle realizzazioni di caso d'uso a livello di progettazione.
Discipline: Analisi e progettazione
Scopo
  • Perfezionare la realizzazione del caso d'uso in termini di interazioni
  • Perfezionare i requisiti delle operazioni delle classi di progettazione
  • Perfezionare i requisiti delle operazioni dei sottosistema di progettazione e/o delle loro interfacce
  • Perfezionare i requisiti delle operazioni sulle capsule
Relazioni
Descrizione principale

Il comportamento di un sistema può essere descritto utilizzando una serie di tecniche, collaborazioni o interazioni. Questo compito descrive l'uso di iterazioni, in particolare diagrammi di sequenza, per illustrare il comportamento del sistema. I diagrammi di sequenza sono molto utili dove il comportamento del sistema o sottosistema può essere descritto principalmente tramite messaggistica sincrona. La messaggistica asincrona, in particolare nei sistemi basati sugli eventi, viene spesso semplicemente descritta in termini di macchine a stati e collaborazioni, permettendo di definire le possibili iterazioni tra oggetti in modo compatto. I messaggi asincroni ricoprono un ruolo importante nei sistemi in tempo reale o reattivi, e sono utilizzati per le comunicazioni tra istanze di  Prodotti di lavoro: Capsule.

 Rappresentazione UML 1.x

È possibile utilizzare una classe proxy per rappresentare il sottosistema in diagrammi sequenza. La classe proxy è contenuta all'interno del sottosistema ed è utilizzata per rappresentarlo in diagrammi che non supportano l'uso diretto di pacchetti e sottosistemi come elementi di comportamento. Utilizzarla dove si vuole mostrare che un sottosistema specifico risponde ad un messaggio. In questo caso, si potranno mostrare i messaggi inviati dal proxy del sottosistema ad altri oggetti.

Per ulteriori informazioni consultare Differenze fra UML 1.x e UML 2.0.

Passi
Creazione delle realizzazioni dei casi d'uso

Il Prodotto di lavoro: Progettazione della realizzazione di caso d'uso consente di tracciare il comportamento del modello di progettazione fino al modello del caso d'uso, ed organizza le collaborazioni nel modello di progettazione sulla base del concetto del caso d'uso.

Creare una realizzazione del caso d'uso di progettazione nel modello di progettazione per ciascun caso d'uso da progettare. Il nome deve essere uguale a quello del caso d'uso associato, ed è necessario stabilire una relazione "realizza" tra essi.

Descrizione delle iterazioni tra oggetti di progettazione

Per ciascuna realizzazione di caso d'uso, è possibile illustrare le interazioni tra gli oggetti di progettazione partecipanti creando uno o più diagrammi sequenza. Delle versioni precedenti potranno essere state create durante Compito: Analisi del caso d'uso. Tali "versioni di analisi" della realizzazione del caso d'uso descrivono le interazioni tra classi di analisi. Queste dovranno essere sviluppate in modo da descrivere le interazioni tra elementi di progettazione.

L'aggiornamento dei diagrammi sequenza prevede i seguenti passi:

  • Identificazione di ciascun oggetto che partecipa nel flusso del caso d'uso. Ciò avviene tramite l'istanziamento delle classi di progettazione e dei sottosistemi identificati Compito: Identificazione degli elementi della progettazione. Nei sistemi in tempo reale si identificheranno anche le istanze di capsule che partecipano nel flusso del caso d'uso.
  • Rappresentazione di ciascun oggetto partecipante in un diagramma sequenza. Definire un ciclo di vita di ciascun oggetto partecipante nel diagramma sequenza. Nella rappresentazione di un sottosistema di progettazione si hanno delle scelte:
    • Si potranno mostrare le istanze del sottosistema nel diagramma sequenza.
    • Si potranno utilizzare le interfacce realizzate dal sottosistema. Questa opzione è preferibile nei casi in cui si vuole mostrare che l'elemento del modello che realizza la stessa interfaccia potrebbe essere utilizzato al suo posto. Se si sceglie di mostrare le interfacce nei diagrammi sequenza, accertarsi che non vi saranno messaggi inviati dall'interfaccia ad altri oggetti. Il motivo è che le interfacce incapsulano in modo completo la realizzazione interna delle proprie operazioni. Non si potrà quindi essere sicuri che tutti gli elementi del modello che realizzano l'interfaccia vengano progettati effettivamente allo stesso modo. È quindi necessario che nei diagrammi sequenza non vengano mostrati messaggi inviati dalle interfacce.
    • È possibile utilizzare il componente per rappresentare il sottosistema in diagrammi sequenza. Utilizzarli dove si vuole mostrare che un sottosistema specifico risponde ad un messaggio. In questo caso, si potranno mostrare i messaggi inviati dal componente ad altri oggetti.

    Notare che questi sono diagrammi sequenza a livello di sistema, che mostrano come interagiscono le istanze di elementi di progettazione di livello superiore (solitamente sottosistemi e interfacce di sottosistema). I diagrammi sequenza che mostrano il progetto interno dei sottosistemi vengono prodotti separatamente, come parte della Compito: Progettazione del sottosistema.

  • Notare che le interazioni degli oggetti attivi vengono solitamente descritte utilizzando collaborazioni di specifiche e macchine a stati. Esse verranno utilizzate in questo contesto per mostrare come i messaggi possano essere inviati agli oggetti attivi da altri elementi del sistema in realizzazioni di casi d'uso più grandi. Nel loro utilizzo tipico, gli oggetti attivi vengono incapsulati all'interno dei sottosistemi per realizzare il compito, tanto che la realizzazione di caso d'uso consiste di una serie di sottosistemi interattivi. Le interazioni definiscono le responsabilità e le interfacce dei sottosistemi. All'interno dei sottosistemi, gli oggetti attivi rappresentano thread simultanei di esecuzione. I sottosistemi consentono al lavoro di essere distribuito tra i team di sviluppo, con le interfacce che fungono da contratti formali tra di essi. Per i sistemi in tempo reale si utilizzeranno le  Prodotto di lavoro: Capsule per rappresentare gli oggetti attivi.

    Una nota minore sulla visualizzazione dei messaggi emanati dai sottosistemi: restringendo i messaggi solo alle interfacce si riducono le dipendenze tra elementi del modello e si migliora l'elasticità della progettazione. Dove possibile si deve cercare di raggiungere tale configurazione, e nei casi in cui vi siano messaggi emanati da sottosistemi a elementi del modello che non siano interfacce, si deve cercare di modificarli come messaggi ad interfacce per migliorare l'indipendenza del modello.

  • Rappresentare le interazioni con gli attori. Rappresentare ciascuna istanza di attore ed oggetto esterno con cui l'oggetto partecipante interagisce con un ciclo di vita nel diagramma sequenza.
  • Illustrare i messaggi scambiati tra oggetti partecipanti. Il flusso degli eventi inizia partendo dalla sommità del diagramma e proseguendo verso il basso, indicando un asse cronologico verticale. Illustrare i messaggi scambiati tra gli oggetti creando messaggi (frecce) tra i cicli di vita. Il nome del messaggio dovrebbe essere il nome dell'operazione da esso richiesta. Nelle fasi iniziali della progettazione, non verranno assegnate molte operazioni agli oggetti, quindi potrebbe essere necessario mettere da parte questa informazione ed assegnare al messaggio un nome temporaneo, tali messaggi sono definiti come "non assegnati". In seguito, quando si saprà di più sulle operazioni degli oggetti partecipanti, si dovrà aggiornare il diagramma "assegnando" il messaggio a queste operazioni.
  • Descrivere cosa fa un oggetto quando riceve il messaggio. Ciò si effettua allegando uno script al messaggio corrispondente. Posizionare questo script a margine del diagramma. Utilizzare testo strutturato o pseudo codice. Se si utilizza lo pseudo codice, usare i costrutti del linguaggio di implementazione così da semplificare l'implementazione delle operazioni corrispondenti. Quando una persona responsabile di una classe dell'oggetto, assegna e definisce le sue operazioni, gli script dell'oggetto forniscono le basi per questo lavoro.

Diagramma descritto nel testo associato.

Il comportamento di un caso d'uso eseguito dagli oggetti viene documentato in un diagramma sequenza.

Una volta distribuito il comportamento tra gli oggetti, si dovrà considerare come verrà controllato il flusso. Gli oggetti sono stati trovati assumendo che essi avrebbero interagito in un determinato modo nella realizzazione di caso d'uso, con un certo ruolo. Quando si distribuisce il comportamento, si potrà iniziare a verificare tale assunto. In alcune parti del flusso si potrebbe voler utilizzare una struttura decentralizzata; in altre invece se ne potrebbe preferire una centralizzata. Per una definizione di queste varianti e per consigli sulla scelta tra i due tipi di struttura, consultare Tecnica: Diagrammi sequenza.

A questo punto si potrebbe aver bisogno di nuovi oggetti, se, ad esempio, si sta utilizzando una struttura centralizzata e si necessita di un nuovo oggetto per controllare il flusso. Ricordarsi che qualsiasi oggetto si aggiunge al modello di progettazione deve soddisfare i requisiti definiti nel modello dell'oggetto.

Incorporazione di meccanismi di progettazione applicabili

Durante il Compito: Analisi strutturale, sono stati identificati i meccanismi di analisi. Durante il Compito: Identificazione dei meccanismi di progettazione, i meccanismi di analisi vengono perfezionati in meccanismi di progettazione, l'associazione tra meccanismi di analisi e di progettazione è registrata nel documento dell'architettura software, ed i meccanismi di progettazione vengono documentati nelle  Linee guida specifiche per progetto.  

Durante questo compito, progettazione del caso d'uso, qualsiasi meccanismo di progettazione applicabile viene incorporato nella realizzazione del caso d'uso. Il progettista valuta i meccanismi di progettazione disponibili e determina quelli applicabili alla realizzazione del caso d'uso in fase di sviluppo, lavorando con i consigli e le linee guida contenute nel Documento dell'architettura software e nelle Linee guida di progettazione.   
Nota: I meccanismi di progettazione potrebbero essere stati identificati nel Compito: Analisi del caso d'uso, durante il quale le classi di analisi potrebbero essere state codificate con un determinato meccanismo di analisi, indicando che una determinata parte della funzionalità doveva essere gestita nella progettazione. In tal caso, i meccanismi di progettazione applicabili sono quelli associati al meccanismo di analisi con cui le classi di analisi partecipanti alla realizzazione di caso d'uso sono state codificate.

Il progettista incorpora i meccanismi di progettazione applicabili nella realizzazione del caso d'uso, includendo gli elementi di progettazione e le loro interazioni necessarie, seguendo le regole documentate nelle Linee guida di progettazione.

Gestione di tutte le varianti del Flusso di eventi

È necessario descrivere qualsiasi variante del flusso in un diagramma sequenza separato. Quando il diagramma deve contenere il livello di dettaglio solitamente necessario in fase di progettazione del sistema, i diagramma sequenza sono generalmente preferibili a quelli di comunicazione perché sono più semplici da leggere.

Iniziare con una descrizione del flusso di base, che è quello più comune ed importante. Passare quindi alla descrizione delle varianti quali i flussi eccezionali. Non è necessario descrivere tutti i flussi di eventi, fin quando si vogliono assumere ed esemplificare tutte le operazioni degli oggetti partecipanti. Dato ciò, i flussi molto semplici potranno essere omessi, come quelli che riguardano un unico oggetto.

Studiare il caso d'uso per verificare la presenza altre varianti di flusso oltre a quelle descritte nella registrazione dei requisiti e nell'analisi, quelli che dipendono dall'implementazione. Quando si identificano nuovi flussi descriverli in un diagramma sequenza. Alcuni esempi di flussi eccezionali comprendono i seguenti.

  • Gestione dell'errore. L'errore riportato da un'interfaccia nella sua comunicazione con un sistema esterno, verrà gestito da questo caso d'uso. Una possibile soluzione potrebbe essere quella di aprire un nuovo percorso di comunicazione.
  • Gestione time-out. Se l'utente non risponde in un determinato periodo di tempo, il caso d'uso dovrà prendere delle misure speciali.
  • Gestione di input errati all'oggetto che partecipa nel caso d'uso. Errori simili potrebbero essere generati da input errati provenienti dall'utente.

Gestione delle parti facoltative del caso d'uso

È possibile descrivere un percorso di flusso alternativo come un flusso facoltativo piuttosto che come variante. L'elenco che segue contiene due esempi di flussi facoltativi.

  • Inviando un segnale, un attore decide, tra una serie di opzioni, cosa il caso d'uso deve fare dopo. Il caso d'uso ha chiesto all'attore di rispondere sì o no ad una domanda, ad esempio, o gli ha sottoposto una varietà di funzioni che il sistema potrà eseguire in questo stato.
  • Il percorso del flusso varia in base al valore degli attributi archiviati o delle relazioni. Il flusso di eventi successivo dipende dal tipo di dati da elaborare.

Se si vuole che un flusso facoltativo, o un qualsiasi flusso secondario complesso, sia rilevante, utilizzare un diagramma sequenza separato. Ciascun diagramma sequenza deve essere referenziato da un diagramma sequenza del flusso di eventi principale utilizzando script, testo a margine o note, per indicare dove si verifica il comportamento del flusso facoltativo o secondario.

Nei casi in cui il comportamento del flusso eccezionale o facoltativo si possa verificare ovunque, ad esempio un comportamento che si esegue al verificarsi di un determinato evento, il diagramma sequenza del flusso di eventi principale dovrà contenere una nota per indicare che quando si verifica l'evento, verrà eseguito il comportamento descritto nel diagramma sequenza facoltativo/eccezionale. In alternativa, se vi fossero comportamenti significativi basati su eventi, considerare l'utilizzo di diagrammi di stato per descrivere il comportamento del sistema. Per ulteriori informazioni, consultare Linee guida: Diagramma di stato.

Semplificazione dei diagrammi sequenza utilizzando i sottosistemi (facoltativo)

Quando si realizza un caso d'uso il flusso di eventi viene solitamente descritto in termini di oggetti eseguiti, cioè come interazione tra oggetti di progettazione. Per semplificare i diagrammi ed identificare comportamenti riutilizzabili, potrebbe essere necessario incapsulare un flusso secondario di eventi all'interno di un sottosistema. In questi casi ampie sezioni secondarie del diagramma sequenza vengono sostituite con un singolo messaggio al sottosistema. All'interno del sottosistema, un diagramma sequenza separato potrà illustrare le interazioni interne nel sottosistema che fornisce il comportamento richiesto (per ulteriori informazioni, consultare Compito: Progettazione del sottosistema).

Le sequenze secondarie di messaggi interni ad un diagramma sequenza devono essere incapsulate nel sottosistema quando:

  • Si verificano ripetutamente in diverse realizzazioni del caso d'uso; cioè, lo stesso (o simile) messaggio viene inviato allo stesso (o simile) oggetto, fornendo lo stesso risultato finale. La parola 'simile' è utilizzata perché alcuni lavori di progettazione potrebbero essere necessari per rendere riutilizzabile il comportamento.
  • Si verifica in un'unica realizzazione del caso d'uso, ma si prevede che venga eseguita ripetutamente in iterazioni future, o in sistemi simili. Il comportamento potrebbe essere utile come componente riutilizzabile.
  • Si verifica in un'unica realizzazione di caso d'uso, ma è complessa e facilmente incapsulabile, deve essere di responsabilità di una persona o di un team, e fornisce un risultato ben definibile. In queste situazioni, il comportamento complesso richiede una conoscenza tecnica particolare, o una conoscenza del dominio, e di conseguenza è adatta all'incapsulamento in un sottosistema.
  • Si determina che essa venga incapsulata in un componente sostituibile (consultare Concetto: Componente). In tal caso un sottosistema è la rappresentazione adeguata per il componente nel modello di progettazione.

Diagramma descritto nel testo associato.

Una realizzazione di caso d'uso può essere descritta, se necessario, in diversi livelli della gerarchia del sottosistema. I cicli di vita del diagramma centrale rappresentano sottosistemi; le interazioni nei cerchi rappresentano le interazioni interne dei membri in risposta ai messaggi.

I vantaggi di un tale approccio sono:

  • Le realizzazioni del caso d'uso diventano meno confuse, in particolare se la progettazione interna di alcuni sottosistemi è complessa.
  • Le realizzazioni del caso d'uso potranno essere create prima della progettazione interna dei sottosistemi; ciò è utile ad esempio in ambienti di sviluppo paralleli (consultare "Come lavorare in parallelo").
  • Le realizzazioni del caso d'uso diventano più generiche e quindi più semplici da modificare, in particolare se un sottosistema deve essere sostituito con un altro.

Esempio:

Considerare il seguente diagramma sequenza, che è parte della realizzazione del caso d'uso Chiamata locale:

Diagramma descritto nel testo associato.

In questo diagramma le classi grigie appartengono al sottosistema di gestione della rete; le altre al sottosistema di gestione dell'abbonato telefonico. Ciò significa che si tratta di un diagramma sequenza a più sottosistemi, cioè un diagramma dove tutti gli oggetti che partecipano al flusso di eventi sono inclusi, senza considerare se le loro classi si trovano in sottosistemi diversi o meno.

Come alternativa si può mostrare la richiesta di comportamento nel sottosistema di gestione della rete, e l'esercizio di interfacce particolari su questo sottosistema. Supponendo che il sottosistema di gestione della rete fornisca un'interfaccia ICoordinator, utilizzata dal sottosistema di gestione dell'abbonato telefonico:

Diagramma descritto nel testo associato.

L'interfaccia ICoordinator viene realizzata dalla classe Coordinatore interna alla gestione della rete. Si potrà utilizzare, così, il sottosistema di gestione della rete stesso e la sua interfaccia ICoordinator nel diagramma sequenza, invece di istanze di classi interne alla gestione della rete:

Diagramma descritto nel testo associato.

Notare che le istanze delle classi Coordinatore, Informazioni digitali e rete sono sostituite dai sottosistemi che le contengono. Tutte le chiamate al sottosistema sono invece realizzate tramite l'interfaccia ICoordinator.

Visualizzazione delle interfacce con ciclo di vita

Per poter raggiungere una vera sostituibilità dei sottosistemi che realizzano la stessa interfaccia, solo le loro interfacce dovranno essere visibili nelle interazioni (e nei diagrammi in generale); altrimenti dovranno essere modificate quando si scambiano i sottosistemi.

Esempio:

Si può includere unicamente l'interfaccia ICoordinator, ma non il sottosistema che la fornisce, nel diagramma sequenza:

Diagramma descritto nel testo associato.

L'invio di un messaggio ad un ciclo di vita di un'interfaccia significa che qualsiasi sottosistema che realizza l'interfaccia potrà essere sostituito al posto dell'interfaccia nel diagramma. Notare che il ciclo di vita dell'interfaccia ICoordinator non ha messaggi in uscita, poiché i diversi sottosistemi che la realizzano possono inviare diversi messaggi. Tuttavia, se si vuole descrivere quale messaggio dovrebbe essere inviato (o consentito) da ciascun sottosistema che realizza l'interfaccia, lo si potrà far uscire dal ciclo di vita dell'interfaccia.

Come lavorare in parallelo

In alcuni casi potrebbe essere appropriato sviluppare un sottosistema più o meno indipendente e parallelo allo sviluppo di altri sottosistemi. Per farlo si dovranno in primo luogo individuare le dipendenze del sottosistema identificando le interfacce esistenti tra essi.

Procedere come segue:

  1. Concentrare i requisiti riguardanti le interfacce tra i sottosistemi.
  2. Evidenziare le interfacce necessarie, mostrando i messaggi che supereranno il confine del sottosistema.
  3. Creare un diagramma sequenza in termini di sottosistemi per ciascun caso d'uso.
  4. Perfezionare le interfacce necessarie per fornire un messaggio.
  5. Sviluppare ciascun sottosistema in parallelo, ed utilizzare le interfacce come strumenti di sincronizzazione tra i team di sviluppo.

Si potrà anche decidere se organizzare i diagrammi sequenza in termini di sottosistemi o delle loro interfacce. In alcuni progetti, potrebbe anche essere necessario implementare le classi che forniscono le interfacce prima di proseguire con la modellazione.

Descrizione dei comportamenti relativi alla persistenza

L'obiettivo del paradigma orientato ad oggetti è quello di incapsulare i dettagli dell'implementazione. Perciò in relazione alla persistenza si desidera ottenere un oggetto permanente che assomigli a quello transitorio. Non si deve necessariamente essere a conoscenza del fatto che l'oggetto sia permanente, o gestirlo in modo diverso da qualsiasi altro oggetto. Almeno questo è l'obiettivo.

In pratica ci potranno essere delle volte in cui l'applicazione debba controllare diversi aspetti della persistenza:

  • quando gli oggetti permanenti vengono letti o scritti
  • quando gli oggetti permanenti vengono eliminati
  • come vengono gestite le transazioni
  • come si raggiunge il controllo del blocco e della simultaneità

Scrittura degli oggetti permanenti

Vi sono due case da considerare: la prima volta che l'oggetto viene scritto nell'archivio persistente, e le volte successive in cui l'applicazione deve aggiornare l'archivio dell'oggetto permanente con modifiche all'oggetto.

In entrambi i casi, il meccanismo specifico dipende dalle operazioni supportate dal framework di persistenza. In generale, il meccanismo utilizzato è quello di inviare un messaggio al framework di persistenza per creare un oggetto permanente. Una volta che l'oggetto è permanente, il framework di persistenza è abbastanza "intelligente" da rilevare le modifiche successive e scriverle nell'archivio dell'oggetto permanente quando necessario (solitamente quando è in corso una transazione).

Un esempio di creazione di un oggetto permanente è riportato di seguito:

Diagramma descritto nel testo associato.

L'oggetto PersistenceMgr è un'istanza di VBOS, un framework di persistenza. OrderCoordinator crea un ordine persistente inviandolo come argomento di un messaggio 'createPersistentObject' a PersistenceMgr.

È generalmente non necessario modellare ciò in maniera esplicita, a meno che non sia importante sapere che l'oggetto sia stato archiviato in modo esplicito in un determinato punto di una sequenza di eventi. Se delle operazioni successive dovranno effettuare una query sull'oggetto, esso dovrà essere presente nel database, e quindi sarà importante sapere che sarà presente in quel punto.

Lettura degli oggetti permanenti

È necessario recuperare l'oggetto dall'archivio degli oggetti permanenti prima che l'applicazione possa inviargli un messaggio. Ricordarsi che il lavoro in un sistema orientato agli oggetti viene eseguito inviando messaggi agli oggetti. Ma se l'oggetto a cui di vuole inviare un messaggio è nel database e non ancora in memoria, allora c'è un problema: non si può inviare un messaggio a qualcosa che non esiste ancora!

In breve, si deve inviare un messaggio ad un oggetto che sa come effettuare una query ad un database, recuperare l'oggetto corretto, ed istanziarlo. Quindi, e solo allora, sarà possibile inviare il messaggio originario come inteso. L'oggetto che istanzia l'oggetto permanente viene a volte definito oggetto factory. Un oggetto factory è responsabile della creazione di istanze di oggetti, compresi quelli permanenti. Data una query, l'oggetto factory potrà essere progettato per restituire una serie di uno o più oggetti che corrispondono ad essa.

Generalmente gli oggetti sono molto collegati tra loro tramite le associazioni, quindi sarà solitamente necessario recuperare unicamente l'oggetto principale di un grafico di oggetti; i rimanenti verranno 'tirati' fuori in modo trasparente dal database tramite le loro associazioni con l'oggetto principale. (Un buon meccanismo di persistenza prevede ciò: recupera gli oggetti solo quando sono necessari; altrimenti, si potrebbero istanziare un ampio numero di oggetti inutilmente. Il recupero di oggetti prima dell'effettiva necessità è uno dei principali di problemi di prestazioni causato da meccanismi di persistenza semplicistici.)

L'esempio che segue illustra come modellare il recupero di oggetti da un archivio di oggetti permanenti. In un effettivo diagramma sequenza, il DBMS non verrebbe mostrato, siccome dovrebbe essere incapsulato in un oggetto factory.

Diagramma descritto nel testo associato.

Eliminazione degli oggetti permanenti

Il problema con gli oggetti permanenti è che sono permanenti! A differenza degli oggetti transitori che scompaiono con il processo che li ha creati, quelli permanenti continuano ad esistere fin quando non vengono esplicitamente eliminati. È quindi importante cancellare l'oggetto quando non lo si utilizza più.

Il problema è che ciò è difficile da determinare. Il fatto che un'applicazione abbia finito di utilizzare un oggetto non significa che altre applicazioni, presenti e future, non debbano utilizzarlo. E siccome gli oggetti possono ed hanno associazioni di cui essi stessi non sono a conoscenza, non è sempre facile capire se è possibile cancellarli.

In progettazione questo potrà essere rappresentato semanticamente utilizzando diagrammi di stato: quando un oggetto raggiunge lo stato fine, potrà essere rilasciato. Gli sviluppatori responsabili dell'implementazione di classi permanenti potranno utilizzare le informazioni del diagramma di stato per richiedere al comportamento del meccanismo di persistenza adeguato di rilasciare l'oggetto. La responsabilità del progettista della realizzazione di caso d'uso è quella di richiamare le operazioni appropriate che causino il raggiungimento dello stato fine da parte dell'oggetto quando è giusto che questo venga eliminato.

Se un oggetto è ampiamente connesso ad altri oggetti, potrebbe essere difficile determinare se potrà essere eliminato. Poiché gli oggetti factory sono a conoscenza della struttura dell'oggetto quanto l'oggetto a cui sono connessi, è spesso utile caricare l'oggetto factory con una classe che abbia la responsabilità di determinare se una particolare istanza può essere eliminata. Il framework della persistenza potrà anch'esso fornire supporto per questa capacità.

Modellazione delle transazioni

Le transazioni definiscono una serie di invocazioni di operazioni che sono atomiche; o sono tutte eseguite o nessuna lo è. Nel contesto della persistenza, una transazione definisce una serie di modifiche su una serie di oggetti che saranno eseguite tutte o nessuna. Le transazioni consentono congruenza, assicurando che le serie di oggetti si spostino da una stato coerente ad un altro.

Vi sono diverse opzioni per mostrare le transazioni nelle realizzazioni del caso d'uso:

  • Testo. Utilizzando degli script a margine di diagrammi sequenza, i confini della transazione potranno essere documentati come mostrato di seguito. Questo metodo è semplice e consente di utilizzare un qualsiasi numero di meccanismi per implementare la transazione.

Diagramma descritto nel testo associato.

Rappresentazione dei confini della transazione utilizzando annotazioni di testo.

  • Utilizzando messaggi espliciti. Se il meccanismo di gestione della transazione utilizzato fa uso di messaggi espliciti per avviare e terminare una transazione, questi potranno essere mostrati esplicitamente nel diagramma sequenza, come riportato di seguito:

Diagramma descritto nel testo associato.

Un diagramma sequenza che mostra messaggi espliciti per avviare e terminare una transazione.

Gestione delle condizioni di errore

Se tutte le operazioni specificate in una transazione non potranno essere eseguite (solitamente perché si è verificato un errore), la transazione viene interrotta, e tutte le modifiche effettuate vengono annullate. Le condizioni di errore previste spesso rappresentano flussi di eventi eccezionali nel caso d'uso. In altri casi, le condizioni di errore si verificano a causa di un errore nel sistema. Le condizioni di errore devono essere documentate nelle interazioni. Gli errori semplici e le eccezioni potranno essere mostrate nelle interazioni in cui si verificano; gli errori complessi e le eccezioni potrebbero necessitare di interazioni proprie.

Le modalità di errore di oggetti specifici potranno essere visualizzate in diagrammi di stato. La gestione del flusso di controllo condizionato di queste modalità di errore potrà essere visualizzata nell'interazione in cui l'errore o l'eccezione si verificano.

Gestione del controllo della simultaneità

La simultaneità descrive il controllo dell'accesso a risorse di sistema critiche nel corso di una transazione. Per poter mantenere il sistema in uno stato congruente, una transazione potrebbe richiedere che esso abbia accesso esclusivo a determinate risorse chiave. L'esclusività potrebbe includere la capacità di leggere e/o scrivere in una serie di oggetti.

Di seguito viene riportato un semplice esempio del perché potrebbe essere necessario restringere l'accesso ad una serie oggetti. Si supponga di lavorare su semplice sistema di immissione di ordini. Le persone chiamano per immettere gli ordini, questi vengono elaborati ed inviati. L'ordine potrebbe essere considerato come una specie di transazione.

Per illustrare la necessità di un controllo della simultaneità, supponiamo che arrivi un ordine per un nuovo paio di scarponi da escursione. Quando l'ordine viene immesso nel sistema, questo controlla se gli scarponi della misura richiesta sono in magazzino. Se vi sono, verranno riservati, così che nessuno li possa comprare prima dell'invio dell'ordine. Una volta inviato l'ordine, gli scarponi vengono rimossi dal magazzino.

Nel periodo che intercorre tra l'immissione dell'ordine ed il suo invio, gli scarponi saranno in uno stato particolare, saranno in magazzino, ma "dedicati" all'ordine immesso. Se l'ordine venisse annullato per una qualsiasi ragione, gli scarponi verranno riportati in magazzino. Una volta inviato l'ordine, si assume che la società non voglia mantenere un record che indichi che prima c'erano gli scarponi.

L'obiettivo della simultaneità, come quello delle transazioni, è di assicurare che il sistema si sposti da uno stato congruente ad un altro. Inoltre la simultaneità si sforza di assicurare che la transazione abbia tutte le risorse necessarie per completare il lavoro. Il controllo della simultaneità può essere implementato in molti modi diversi, compreso il blocco delle risorse, semafori, blocco della memoria condivisa e spazi di lavoro privati.

In un sistema orientato ad oggetti, è difficile dire, basandosi sui soli pattern di messaggio, se un determinato messaggio possa causare il cambiamento di stato di un oggetto. Inoltre, implementazioni differenti potranno ovviare alla necessità di restringere l'accesso a determinati tipi di risorse; ad esempio, alcune implementazioni forniscono a ciascuna transazione la propria vista dello stato del sistema al loro inizio. In questo caso, altri processi potranno modificare lo stato di un oggetto senza influenzare la 'vista' di qualsiasi altra transazione in esecuzione.

Per evitare di limitare l'implementazione, nella progettazione si indicheranno semplicemente le risorse a cui la transazione deve avere accesso esclusivo. Utilizzando l'esempio precedente, si vuole indicare che si necessita di accesso esclusivo agli scarponi ordinati. Un'alternativa semplice è quella di annotare una descrizione del messaggio inviato, indicando che l'applicazione necessità di controllo esclusivo sull'oggetto. L'implementatore utilizzerà questa informazione per determinare il miglior modo per implementare i requisiti di simultaneità. Un diagramma sequenza di esempio che mostra le annotazioni di quali messaggi richiedono accesso esclusivo è riportato di seguito. Si assume che tutti i blocchi vengono rilasciati quando la transazione è completata.

Diagramma descritto nel testo associato.

Esempio che mostra il controllo accessi annotato in un diagramma sequenza.

Il motivo per cui non si restringe l'accesso a tutti gli oggetti necessari in una transazione è che spesso solo pochi oggetti devono avere delle restrizioni di accesso; limitare l'accesso a tutti gli oggetti partecipanti in una transazione fa perdere risorse valide e può creare, piuttosto che prevenire, dei colli di bottiglia delle prestazioni.

Perfezionamento della descrizione del flusso di eventi

Nel flusso di eventi della realizzazione di caso d'uso potrebbe essere necessario integrare la descrizione del diagramma sequenza, nei casi in cui il flusso di eventi non risulti abbastanza chiaro dall'analisi dei messaggi inviati tra oggetti partecipanti. Alcuni esempi comprendono l'annotazione dei tempi, note su comportamenti condizionali o chiarimenti sui comportamenti delle operazioni, necessari per semplificare la lettura dei diagrammi da parte degli osservatori esterni.

Il flusso di eventi è inizialmente abbozzato nel Compito: Analisi del caso d'uso. In questa fase si perfezionerà in modo da chiarire il diagramma sequenza.

Spesso il nome dell'operazione non è sufficiente per comprendere perché questa viene eseguita. Potrebbero essere necessarie note di testo o script a margine del diagramma per chiarire il diagramma sequenza. Queste potrebbero anche essere utili per rappresentare il flusso di controllo nei passi decisionali, loop e branching. Inoltre si potrebbe necessitare di codice di testo per correlare i punti di estensione nel caso d'uso con posizioni specifiche nel diagramma sequenza.

Esempi precedenti in questo compito hanno illustrato una serie di modi diversi per immettere delle annotazioni nel diagramma sequenza.



Unificazione delle classi di progettazione e dei sottosistemi

Con il realizzarsi dei casi d'uso si dovranno unificare le classi di progettazione identificate ed i sottosistemi per assicurare l'omogeneità e la congruenza nel Modello di progettazione.

Punti da considerare:

  • I nomi degli elementi del modello devono descrivere le loro funzioni.
  • Evitare nomi simili e sinonimi perché rendono difficile la distinzione tra elementi del modello.
  • Unire gli elementi del modello che definiscono comportamenti simili, o che rappresentano lo stesso fenomeno.
  • Unire le classi di entità che rappresentano lo stesso concetto o hanno gli stessi attributi, anche se il loro comportamento definito è diverso.
  • Utilizzare l'ereditarietà per gli elementi del modello astratti, che rende il modello più solido.
  • Quando si aggiornano gli elementi del modello aggiornare anche la descrizione del flusso di eventi corrispondente alla realizzazione del caso d'uso.
Valutazione dei propri risultati

Controllare il modello di progettazione in questa fase per verificare che il proprio lavoro vada nella giusta direzione. Non è necessario revisionare il modello in dettaglio, ma è bene tenere presente il modello di progettazione mentre ci si sta lavorando.

Consultare in modo particolare Realizzazione del caso d'uso nel Compito: Revisione della progettazione.

Ulteriori informazioni