Le classi di analisi possono essere stereotipate in una delle seguenti:
-
Classi di boundary
-
Classi di controllo
-
Classi di entità
Oltre a fornire una guida specifica del processo durante la rilevazione di classi, questa stereotipizzazione dà come
risultato un modello di oggetto solido perché le modifiche al modello tendono a influenzare solo una specifica area. Ad
esempio, le modifiche nell'interfaccia utente influenzeranno solo le classi di boundary. Le modifiche nel flusso di
controllo influenzeranno solo le classi di controllo. Le modifiche nelle informazioni a lungo termine inciderà solo
sulle classi di entità. Tuttavia, tali stereotipi sono utili specialmente come supporto per identificare le classi
nell'analisi e nella progettazione iniziale. Sarebbe opportuno considerare l'utilizzo di una serie di stereotipi
leggermente differente nelle fasi successive della progettazione da correlare meglio all'ambiente di implementazione,
al tipo di applicazione e così via.
Una classe di boundary viene utilizzata per modellare l'interazione fra gli ambienti del sistema e le relative
operazioni interne. Tale interazione implica la trasformazione e la conversione degli eventi e l'individuazione delle
modifiche nella presentazione del sistema (ad esempio nell'interfaccia).
Le classi boundary modellano le parti del sistema che dipendono dai relativi elementi associati. Le classi di entità e
le classi di controllo modellano le parti indipendenti dagli elementi associati al sistema. Quindi, modificando la GUI
o il protocollo di comunicazione, vengono cambiate solo le classi di boundary, non quelle di entità e di controllo.
La classi boundary rendono più semplici la comprensione del sistema perché chiarificano i boundary del sistema. Esse
favoriscono la progettazione fornendo un buon punto di partenza per l'identificazione dei servizi correlati. Ad
esempio, se si identifica l'interfaccia di una stampante all'inizio della progettazione, si noterà subito che occorre
anche modellare la formattazione delle stampe.
Le classi di boundary comuni includono finestre, protocolli di comunicazione, interfacce di stampe, sensori e
terminali. Non è necessario modellare le parti di routine dell'interfaccia, ad esempio i pulsanti, come classi di
boundary separate. Generalmente, l'intera finestra è l'oggetto di boundary definito in modo più dettagliato. Le classi
di boundary sono utili anche per la cattura di interfacce in API non OO (object-oriented), come ad esempio il codice
legacy.
Si consiglia di modellare le classi di boundary in base al tipo di boundary che rappresentano. La comunicazione con un
altro sistema e la comunicazione con un attore umano (tramite un'interfaccia utente) hanno obiettivi molto diversi. Per
la comunicazione con un attore umano, il problema più importante è in che modo l'interfaccia verrà presentata
all'utente. Per la comunicazione con un altro sistema, il problema più importante è il protocollo di comunicazione.
Un oggetto di boundary (un'istanza di una classe boundary) può resistere a un'istanza del caso d'uso se, ad esempio,
deve comparire in una schermata tra le prestazioni dei due casi d'uso. Normalmente, tuttavia, gli oggetti di boundary
rimangono attivi per tutto il tempo dell'istanza del caso d'uso.
Rilevazione delle classi boundary
Una classe boundary è l'intermediario tra l'interfaccia e un elemento al di fuori del sistema. Gli oggetti di boundary
isolano il sistema dalle modifiche negli elementi associati (modifiche nelle interfacce in altri sistemi, modifiche nei
requisiti dell'utente, ecc.), impedendo che tali modifiche influiscano sul resto del sistema.
Un sistema può avere diversi tipi di classi boundary:
-
Classi di interfacce utente - classi che mediano la comunicazione con gli utenti del sistema
-
Classi di interfacce del sistema - classi che mediano la comunicazione con altri sistemi
-
Classi di interfacce dell'unità - classi che forniscono l'interfaccia alle unità (ad esempio i sensori), che
rilevano gli eventi esterni
Rilevazione delle classi di interfacce utente
Definire una classe boundary per ogni coppia di attori del caso d'uso. E' possibile visualizzare questa classe come se
fosse responsabile della coordinazione dell'interazione con l'attore. E' anche possibile definire le classi boundary
aggiuntive per rappresentare le classi sussidiarie a cui la classe boundary primaria delega alcune delle proprie
responsabilità. Ciò vale in modo particolare per le applicazioni GUI basate sulla finestra, in cui è possibile
modellare un oggetto di boundary per ogni finestra o per ogni modulo. Modellare solo le astrazioni chiave del sistema;
non modellare ogni pulsante, elenco e widget nella GUI. L'obiettivo dell'analisi è creare una buona immagine di come è
composto il sistema, non per progettare ogni minimo dettaglio. In altre parole, identificare le classi boundary solo
per fenomeni nel sistema o per elementi menzionati nel flusso di eventi della realizzazione del caso d'uso di
analisi.
Creare bozze o utilizzare dump dello schermo da un Prototipo dell'interfaccia utente, che illustra la funzionalità e
l'aspetto delle classi boundary.
Rilevazione delle classi di interfacce del sistema
Una classe boundary che comunica con un sistema esterno è responsabile per la gestione della comunicazione con il
sistema esterno; essa fornisce l'interfaccia per il sistema che si sta costruendo.
Esempio
In uno sportello automatico, il prelievo di fondi deve essere verificato tramite la relativa rete, un attore (che, a
turno, verifica il prelievo con il sistema di contabilità in banca). Un oggetto, denominato Interfaccia della rete
dello sportello automatico, può essere identificato per fornire la comunicazione con la suddetta rete.
E' possibile che l'interfaccia a un sistema esistente sia già ben definita; in tal caso, le responsabilità dovrebbero
essere derivate direttamente dalla definizione dell'interfaccia. Se esiste una definizione dell'interfaccia formale, è
possibile eseguire il reverse engineering su di essa e non è necessario definirla formalmente; tenere presente solo che
l'interfaccia esistente verrà riutilizzata durante la progettazione.
Rilevazione delle classi dell'interfaccia dell'unità
Il sistema potrebbe contenere elementi che si comportano come se fossero esterni (modificano spontaneamente il valore
senza alcun oggetto nel sistema che li influenzi), ad esempio un sensore. Sebbene sia possibile rappresentare tale tipo
di unità esterna utilizzando gli attori, gli utenti del sistema potrebbero trovare tale operazione "confusionaria",
perché tende a collocare unità e attori umani sullo stesso "livello". Una volta che ci si allontana dai requisiti di
raccolta, tuttavia, è necessario considerare l'origine di tutti gli eventi esterni e accertarsi che il sistema disponga
di un modo per rilevare tali eventi.
Se l'unità è rappresentata come attore nel modello del caso d'uso, è semplice trovare una giustificazione utilizzando
una classe boundary per mediare la comunicazione tra l'unità e il sistema. Se il modello del caso d'uso non include
tali "attori-unità", ora è il momento giusto per aggiungerli, aggiornando le descrizioni supplementari dei casi d'uso,
dove sono necessarie.
Per ogni "attore-unità", creare una classe boundary per catturare le responsabilità dell'unità o del sensore. Se esiste
già un'interfaccia ben definita per l'unità, prenderne nota per un successivo riferimento durante la progettazione.
Una classe di controllo viene utilizzata per modellare la funzionalità del controllo specifica per uno o più
casi d'uso. Gli oggetti di controllo (istanze delle classi di controllo) spesso controllano altri oggetti, quindi la
relativa funzionalità è di tipo coordinante. Le classi di controllo incapsulano la funzionalità specifica del caso
d'uso.
La funzionalità specifica di un oggetto di controllo è strettamente correlata alla realizzazione di un determinato caso
d'uso. In molti scenari, è possibile affermare anche che gli oggetti di controllo "eseguono" le realizzazioni dei casi
d'uso d'analisi. Tuttavia, alcuni oggetti di controllo possono partecipare a più realizzazioni dei casi d'uso d'analisi
se le attività di tali casi d'uso sono strettamente correlate. Inoltre, diversi oggetti di controllo di differenti
classi di controllo possono partecipare a più casi d'uso. Non tutti i casi d'uso richiedono un oggetto di controllo. Ad
esempio, se il flusso di eventi in un caso d'uso è correlato a un oggetto di entità, un oggetto di boundary può
realizzare il caso d'uso in cooperazione con l'oggetto di entità. E' possibile iniziare identificando una classe di
controllo per realizzazione del caso d'uso d'analisi e quindi perfezionarla man mano che vengono identificate ulteriori
realizzazioni e che viene individuata una comunalità.
Le classi di controllo possono contribuire alla comprensione del sistema perché rappresentano la dinamica del sistema,
gestendo le attività e i flussi di controllo principali.
Quando il sistema esegue il caso d'uso, viene creato un oggetto di controllo. Tali oggetti, generalmente, cessano di
esistere una volta eseguito il corrispondente caso d'uso.
Tenere presente che una classe di controllo non gestisce ogni elemento necessario in un caso d'uso. Essa
coordina, invece, le attività di altri oggetti che implementano la funzionalità. La classe di controllo delega il
valore agli oggetti a cui è stata assegnata la responsabilità per la funzionalità.
Rilevazione delle classi di controllo
Le classi di controllo forniscono la funzionalità di coordinazione nel sistema. Il sistema può eseguire alcuni casi
d'uso senza gli oggetti di controllo (utilizzando soltanto gli oggetti di entità e di boundary), in particolare i casi
d'uso che includono solo la semplice gestione delle informazioni memorizzate.
I casi d'uso più complessi generalmente richiedono una o più classi di controllo per coordinare la funzionalità di
altri oggetti nel sistema. Gli esempi di oggetti di controllo includono programmi come i responsabili di transazione, i
coordinatori di risorse e i gestori di errori.
Le classi di controllo separano gli oggetti di boundary e di entità l'uno dall'altro, rendendo il sistema più
tollerante alle modifiche nel boundary del sistema. Essi separano anche la funzionalità specifica del caso d'uso dagli
oggetti di entità, rendendoli più riutilizzabili attraverso i sistemi e i casi d'uso.
Le classi di controllo forniscono una funzionalità che:
-
è indipendente dagli elementi circostanti (non cambia quando cambiano gli elementi circostanti),
-
definisce la logica di controllo (ordine tra eventi) e le transazioni all'interno di un caso d'uso.
-
cambia lievemente se la struttura o la funzionalità interna delle classi di entità viene modificata,
-
utilizza o imposta il contenuto di diverse classi di entità e, quindi, necessita la coordinazione della
funzionalità di tali classi di entità.
-
non viene eseguita nello stesso modo ogni volta che viene attivata (il flusso di eventi caratterizza diversi
stati).
Come stabilire se una classe di controllo è necessaria
Il flusso di eventi di un caso d'uso definisce l'ordine in cui vengono eseguite le differenti attività. Iniziare
cercando di capire se il flusso può essere gestito dalle classi di entità e di boundary già identificate. Per flussi
di eventi semplici che, principalmente, richiamano e visualizzano o modificano le informazioni, una classe di
controllo non viene, generalmente, giustificata; le classi boundary saranno responsabili per il coordinamento del caso
d'uso.
Si consiglia di incapsulare i flussi di eventi in una classe di controllo separata quando è complessa e consiste
in una funzionalità dinamica che può cambiare in modo indipendente dalle interfacce (classi boundary) o dalle
memorizzazioni di informazioni (classi di entità) del sistema. Incapsulando i flussi di eventi, è possibile
riutilizzare la classe di controllo per vari sistemi con interfacce e memorizzazioni dati differenti (o almeno le
strutture di dati sottostanti).
Esempio: gestione di una coda di attività
E' possibile identificare una classe di controllo dal caso d'uso caso d'uso Esecuzione attività nel sistema di gestione
magazzino. Tale classe di controllo gestisce una coda di attività, verificando che le attività vengano eseguite
nell'ordine corretto. Essa esegue la successiva attività nella coda non appena viene assegnata l'attrezzatura di
trasporto appropriata. Il sistema può, quindi, eseguire diverse attività contemporaneamente.
La funzionalità definita dall'oggetto di controllo corrispondente è più semplice da descrivere se la si suddivide in
due classi di controllo: Esecutore compito e Gestore coda. Un oggetto Gestore coda gestirà solo l'ordine della coda e
l'assegnazione dell'attrezzatura di trasporto. Un oggetto Gestore coda è necessario per l'intera coda. Non appena il
sistema esegue un'attività, esso crea un nuovo oggetto Esecutore compito, che eseguirà l'attività. E' quindi necessario
un oggetto Esecutore compito per ogni attività eseguita dal sistema.
Si consiglia di suddividere le classi complesse dovrebbero lungo linee di responsabilità simili.
Il vantaggio principale di questa suddivisione è che sono state separate le responsabilità di gestione coda (elementi
generici per diversi casi d'uso) dalle particolari attività di gestione attività, specifiche per questo caso d'uso. Ciò
rende più semplice la comprensione e l'adattamento delle classi al progredire della progettazione. Vi sono, inoltre,
dei vantaggi nel bilanciamento del carico del sistema, poiché è possibile creare tutti gli Esecutori compito necessari
per gestire il carico di lavoro.
Incapsulamento del flusso di eventi principale e dei flussi di eventi alternativi/eccezionali in classi di controllo
separate
Per semplificare le modifiche, incapsulare il flusso di eventi principale e i flussi di eventi alternativi in classi di
controllo differenti. Se i flussi alternativi ed eccezionali sono completamente indipendenti, separarli. In questo
modo, sarà più semplice l'estensione e la gestione del sistema nel tempo.
Divisione delle classi di controllo in cui due attori condividono la stessa classe
Potrebbe anche essere necessario dividere le classi di controllo quando diversi attori utilizzano la stessa classe. In
tal modo, le modifiche vengono isolate dal resto del sistema, nei requisiti di un attore. Nei casi in cui il costo
della modifica è elevato o le conseguenze estreme, si consiglia di identificare tutte le classi di controllo relative a
uno o più attori e dividerle. Nel caso ideale, ogni classe di controllo dovrebbe interagire (tramite un oggetto di
boundary) con un attore o con nessuno.
Esempio: gestione di una chiamata
Considerare il caso d'uso Chiamata locale. Inizialmente, è possibile identificare una classe di controllo per
gestire la chiamata stessa.
La classe di controllo che gestisce le chiamate del telefono locali in un sistema telefonico possono essere divise,
rapidamente, in due classi di controllo, funzionalità-A e funzionalità-B, una per ogni attore coinvolto.
In una chiamata telefonica locale, sono presenti due attori: abbonato telefonico-A che avvia la chiamata e
abbonato telefonico-B che riceve la chiamata. L'abbonato telefonico-A solleva il ricevitore, sente il
segnale di libero e quindi digita un numero, che il sistema memorizza e analizza. Quando il sistema ha ricevuto tutte
le cifre, invia un segnale di libero all'abbonato telefonico-A e uno squillo all'abbonato telefonico-B.
Quando l'abbonato telefonico-B risponde, il tono e il segnale vengono interrotti e la conversazione tra gli
abbonati può iniziare. La chiamata viene terminata quando entrambi gli abbonati attaccano.
E' necessario controllare due funzionalità: cosa succede a casa dell'abbonato A e cosa succede a casa dell'abbonato B.
Per questo motivo, l'oggetto di controllo originale è stato suddiviso in due oggetti di controllo,
Funzionalità-A e Funzionalità-B.
Non è necessario suddividere una classe di controllo se:
-
Si può avere la certezza che il comportamento degli attori correlati agli oggetti della classe di controllo non
verrà mai modificato o cambierà di poco.
-
La funzionalità di un oggetto della classe di controllo verso un attore è piuttosto insignificante rispetto a
quella di un altro attore, un singolo oggetto può contenere l'intera funzionalità. La combinazione delle
funzionalità in questo modo avrà un effetto trascurabile sulla capacità di cambiamento.
Una classe di entità viene utilizzata per modellare le informazioni e la funzionalità associata che occorre
memorizzare. Gli oggetti di entità (istanze di classi di entità) vengono utilizzati per conservare e aggiornare le
informazioni sullo stesso fenomeno, ad esempio un evento, una persona o un oggetto della vita reale. Essi sono, di
solito, permanenti, dispongono di attributi e relazioni necessari per un lungo periodo, talvolta per l'intera durata
del sistema.
Un oggetto di entità, generalmente, non è specifico per una realizzazione del caso d'uso; a volte, un oggetto di entità
non è neanche specifico per il sistema stesso. I valori dei relativi attributi e relazioni vengono spesso forniti da un
attore. Un oggetto di entità può anche essere necessario per favorire l'esecuzione delle attività di sistema interne.
Gli oggetti di entità possono avere funzionalità complicate come quelle degli altri stereotipi di oggetti. Tuttavia, a
differenza di altri oggetti, questa funzionalità è strettamente correlata al fenomeno che l'oggetto di entità
rappresenta. Gli oggetti di entità sono indipendenti dall'ambiente (gli attori).
Gli oggetti di entità rappresentano i concetti chiave del sistema che si sta sviluppando. Esempi tipici di classi di
entità in un sistema bancario sono Conto e Cliente. In un sistema di gestione rete, gli esempi sono
Nodo e Collegamento.
Se il fenomeno che si desidera modellare non è utilizzato da un'altra classe, è possibile modellarlo come attributo di
una classe di entità o anche come relazione tra classi di entità. Dall'altra parte, se il fenomeno viene utilizzato da
un'altra classe nel modello di progettazione, occorre modellarlo come classe.
Le classi di entità forniscono un altro punto di vista da cui comprendere il sistema, perché mostrano la struttura
logica dei dati, che consente di individuare le possibili offerte del sistema ai propri utenti.
Rilevazione delle classi di entità
Le classi di entità rappresentano memorizzazioni di informazioni nel sistema; esse vengono generalmente utilizzate per
rappresentare i concetti chiave gestiti dal sistema. Gli oggetti di entità sono, spesso, passivi e permanenti. Le loro
responsabilità principali sono la memorizzazione e la gestione delle informazioni nel sistema.
Una fonte di ispirazione frequente per le classi di entità sono il Glossario (sviluppato durante i requisiti) e un
modello di dominio business (sviluppato durante la modellazione business, se tale modellazione è stata eseguita).
E' consentito quanto segue:
-
Comunicazione delle associazioni tra due classi boundary, ad esempio, per descrivere in che modo una specifica
finestra è correlata ad altri oggetti boundary.
-
Comunicazione o sottoscrizione da una classe boundary a una classe di entità, perché gli oggetti boundary
potrebbero dover tenere traccia di determinati oggetti di entità tra azioni nell'oggetto boundary o essere
informati delle modifiche di stato nell'oggetto di entità.
-
Comunicazione di associazioni da una classe boundary a una classe di controllo, in modo che un oggetto boundary
possa attivare una determinata funzionalità.
E' consentito quanto segue:
-
Comunicazione o sottoscrizione tra classi di controllo e classi di entità, perché gli oggetti di controllo
potrebbero dover tenere traccia di determinati oggetti di entità tra azioni nell'oggetto di controllo o essere
informati delle modifiche di stato nell'oggetto di entità.
-
Comunicazione di associazioni tra le classi di controllo e boundary, consentendo la comunicazione dei risultati
della funzionalità richiamata all'ambiente.
-
Comunicazione di associazioni tra classi di controllo, consentendo la costruzione di modelli di funzionalità più
complessi.
La classi di entità dovrebbero essere soltanto la fonte di associazioni (comunicazione o sottoscrizione) ad altre
classi di entità. Gli oggetti della classe di entità dovrebbero essere di lunga durata, a differenza degli oggetti
della classe di controllo e di boundary. Da un punto di vista strutturale, è bene limitare la visibilità che un oggetto
di entità ha dei relativi elementi associati; in tal modo, il sistema è più suscettibile alle modifiche.
FromTo
(navigabilità)
|
Boundary
|
Entità
|
Controllo
|
Boundary
|
comunicazione
|
comunicazione
sottoscrizione
|
comunicazione
|
Entità
|
|
comunicazione
sottoscrizione
|
|
Controllo
|
comunicazione
|
comunicazione
sottoscrizione
|
comunicazione
|
Combinazioni di stereotipi di associazioni valide
-
Quando viene identificata una nuova funzionalità, verificare che sia presente una classe esistente con
responsabilità simili, riutilizzando le classi dove possibile. Solo quando si è certi che non vi è alcun oggetto
esistente che può eseguire la funzionalità, si consiglia di creare nuove classi.
-
Non appena le classi vengono identificate, esaminarle per verificare che abbiano responsabilità coerenti. Quando le
responsabilità delle classi sono sconnesse, suddividere l'oggetto in due o più classi. Aggiornare i diagrammi di
interazione, di conseguenza.
-
Se una classe viene suddivisa perché vengono rilevate responsabilità sconnesse, esaminare le collaborazioni in cui
la classe ha un ruolo, per controllare se è necessario aggiornare la collaborazione. Aggiornare la collaborazione,
se necessario.
-
Una classe con una sola responsabilità non è un problema di per se, ma dovrebbe generare domande solo se
necessario. Essere preparati alla sfida e a giustificare l'esistenza di tutte le classi.
|