Il
modello di progettazione può essere strutturato in piccole unità per renderne più semplice la comprensione.
Raggruppando gli elementi del modello di progettazione in pacchetti e sottosistemi e mostrando come quei raggruppamenti
siano correlati gli uni con gli altri, è più facile comprendere la struttura globale del modello. Un sottosistema di progettazione viene modellato come componente che realizza una o
più interfacce; per ulteriori informazioni, consultare il Prodotto di lavoro: Sottosistema di progettazione e la Linea guida: Sottosistema di progettazione. I pacchetti di progettazione, d'altra
parte, sono solo per il raggruppamento.
Una classe contenuta in un pacchetto può essere pubblica o privata. Una classe pubblica può essere
associata da qualsiasi altra classe. Una classe privata può
essere associata solo dalle classi contenute nel pacchetto.
Un'interfaccia di pacchetto è composta dalle classi pubbliche di un pacchetto. L'interfaccia del pacchetto (classi
pubbliche) isola ed implementa le dipendenze su altri pacchetti. In questo modo viene semplificato lo sviluppo
parallelo poiché è possibile stabilire delle interfacce in precedenza e gli sviluppatori devono conoscere solo le
modifiche nelle interfacce degli altri pacchetti.
È possibile suddividere il modello di progettazione per una serie di motivi:
-
Si possono utilizzare i pacchetti ed i sottosistemi come unità d'ordine, di configurazione o di distribuzione
quando il sistema finito.
-
L'assegnazione delle risorse e la competenza dei diversi team di sviluppo potrebbe richiedere che il progetto venga
suddiviso in gruppi differenti in sedi diverse. I sottosistemi, con le interfacce ben definite, forniscono un
metodo per suddividere il lavoro fra i team in modo controllato e coordinato, consentendo alla progettazione e
all'implementazione di procedere in parallelo.
-
i sottosistemi possono essere utilizzati per strutturare il modello di progettazione in modo da riflettere i tipi
di utenti. Molte delle richieste di modifica hanno origine dagli utenti: i sottosistemi fanno in modo che le
modifiche provenienti da un particolare tipo di utente vengano applicate solo sulle parti del sistema che
corrispondono a quel tipo di utente.
-
In alcune applicazioni, determinate informazioni devono essere accessibili solo a poche persone. I sottosistemi
consentono di mantenere la riservatezza nelle aree in cui è necessaria.
-
Se si sta creando un sistema di supporto, è possibile farlo utilizzando i sottosistemi ed i pacchetti per fornirlo
di una struttura del tutto simile a quella del sistema da supportare. In questo modo è possibile sincronizzare la
manutenzione dei due sistemi.
-
I sottosistemi vengono utilizzati per rappresentare i prodotti ed i servizi esistenti che il
sistema usa (ad esempio, prodotti COTS e librerie), come illustrato nelle prossime sezioni.
Quando le classi boundary vengono distribuite ai pacchetti, possono essere applicate due diverse strategie; la scelta
dipende se in futuro si prevede o meno di modificare in modo significativo le interfacce di sistema.
-
Se è probabile che l'interfaccia di sistema verrà sostituita o subirà delle modifiche importanti, deve essere
separata dal resto del modello di progettazione. Quando viene modificata l'interfaccia utente, verranno implicati
solo quei pacchetti. Un esempio di modifica importante è il passaggio da interfaccia orientata sulle righe a
interfaccia orientata sulle finestre.
Se lo scopo principale è di semplificare delle modifiche significative all'interfaccia, le classi boundary devono
essere collocate in uno o più pacchetti separati.
-
Se non sono previste grosse modifiche all'interfaccia, le modifiche ai servizi di sistema dovrebbero essere il
principio guida, piuttosto che le modifiche all'interfaccia. Le classi boundary allora devono essere collocate
insieme alle classi di entità e di controllo con le quali sono correlate a livello funzionale. In questo modo sarà
facile constatare che le classi boundary verranno implicate, quando viene modificata una determinata classe di
entità o di controllo.
Per semplificare le modifiche ai servizi del sistema, le classi boundary vengono impacchettate insieme alle classi alle
quali sono correlate a livello funzionale.
Le classi boundary obbligatorie che non sono correlate a livello funzionale ad alcuna classe di entità, o di controllo,
devono essere collocate in pacchetti separati, insieme alle classi boundary che appartengono alla stessa interfaccia.
Se una classe boundary è correlata ad un servizio facoltativo, raggrupparla con le classi che collaborano a fornire il
servizio, in un sottosistema separato. Il sottosistema verrà messo in corrispondenza con un altro componente opzionale,
che viene fornito quando viene ordinata la funzionalità opzionale.
Per ogni gruppo di classi correlate a livello funzionale deve essere identificato un pacchetto. Esistono diversi
criteri pratici che possono essere applicati quando si valuta se due classi sono correlate a livello funzionale. Essi
sono, in ordine decrescente di importanza:
-
Se le modifiche alla funzionalità e/o alla struttura di una classe implicano delle modifiche ad un'altra classe, le
due classi sono correlate a livello funzionale.
Esempio
Se viene aggiunto un nuovo attributo alla classe di entità Ordine, con tutta probabilità sarà necessario
aggiornare la classe di controllo Amministratore ordini. Quindi appartengono allo stesso pacchetto
Gestione ordini.
-
E' possibile individuare se una classe è funzionalmente correlata ad un'altra iniziando da una classe, ad esempio
una classe di entità, ed esaminando l'impatto della sua rimozione dal sistema. Qualsiasi classe risulti superflua
dopo la rimozione della classe, è in qualche modo collegata alla classe rimossa. Per superflua si intende che la
classe viene utilizzata solo dalla classe rimossa o che dipende da essa.
Esempio
Nel Sistema di gestione magazzino esiste un pacchetto Gestione ordini che contiene le due classi di
controllo Amministratore ordini e Registro ordini. Entrambe le classi di controllo modellano dei
servizi relativi alla gestione degli ordini nel magazzino. Tutti gli attributi e le relazioni degli ordini sono
memorizzate dalla classe di entità Ordine, che esiste solo per la gestione degli ordini. Se la classe di
entità viene rimossa, non saranno più necessarie Amministratore ordini o Registro ordini perché sono
utili solo se è presente anche Ordine. Quindi la classe di entità Ordine deve essere inclusa nello
stesso pacchetto delle due classi di controllo.
Amministratore ordini e Registro ordini appartengono allo stesso pacchetto di Ordine, poiché
divengono superflue se Ordine viene rimosso dal sistema.
-
Due oggetti possono essere funzionalmente correlati se interagiscono con un grande numero di messaggi o dispongono
di intercomunicazioni altrimenti complicate.
Esempio
La classe di controllo Esecutore compito invia e riceve molti messaggi da e verso l'Interfaccia
trasportatore. Questa è un'altra indicazione che devono essere incluse nello stesso pacchetto, Gestione
compiti.
-
Una classe boundary può essere funzionalmente correlata ad una particolare classe entità se la funzione della
classe boundary è di presentare la classe entità.
Esempio
La classe boundary Modulo bancale nel Sistema di gestione magazzino presenta all'utente un'istanza
della classe di entità Bancale. Ogni Bancale viene rappresentato da un numero di identificazione
sullo schermo. Se le informazioni su un Bancale vengono modificate, ad esempio se gli viene assegnato anche
un nome, potrebbe essere necessario modificare anche la classe boundary. Quindi anche Modulo bancale deve
essere incluso nello stesso pacchetto di Bancale.
-
Due classi possono essere funzionalmente correlate se interagiscono con lo stesso attore o sono influenzate dalle
modifiche apportate ad esso. Se due classi non implicano lo stesso attore, non devono stare nello stesso pacchetto.
L'ultima regola può, naturalmente, essere ignorata per motivazioni più importanti.
Esempio
Nel Sistema di gestione magazzino esiste un pacchetto Gestione compiti, che include, fra le altre
cose, la classe di controllo Esecutore compito. Questo è l'unico pacchetto coinvolto con l'attore
Trasportatore, il trasportatore fisico che può trasportare un bancale nel magazzino. L'attore interagisce
con la classe di controllo Esecutore compito tramite la classe boundary Interfaccia trasportatore.
Questa classe boundary deve quindi essere inclusa nel pacchetto Gestione compiti.
Interfaccia trasportatore e Esecutore compito appartengono allo stesso pacchetto poiché entrambi sono
toccati dalle modifiche all'attore Trasportatore.
-
Due classi possono essere funzionalmente correlate se fra di loro intercorrono delle relazioni fra loro
(associazioni, aggregazioni, ecc.). Naturalmente questo criterio non può essere seguito di routine ma può essere
utilizzato quando non sono applicabili altri criteri.
-
Una classe può essere funzionalmente correlata alla classe che ne crea delle istanze.
Questi due criteri determinano quando due classi non devono essere collocate nello stesso pacchetto:
-
Due classi correlate a due attori diversi non devono essere messe nello stesso pacchetto.
-
Una classe facoltativa ed una obbligatoria non devono stare nello stesso pacchetto.
Innanzitutto tutti gli elementi di un pacchetto devono avere lo stesso tipo di opzionalità: non possono esserci degli
elementi di modello facoltativi in un pacchetto obbligatorio.
Esempio
La classe entità obbligatoria Tipo di articolo ha, fra le altre cose, un attributo denominato Soglia di
ristoccaggio. La funzione di ristoccaggio, tuttavia, è facoltativa nel sistema. Quindi Articolo deve essere
suddiviso in due classi di entità, dove la classe facoltativa è correlata a quella obbligatoria.
Un pacchetto considerato obbligatorio non può dipendere da pacchetti considerati facoltativi.
Di regola, un singolo pacchetto non può essere utilizzato da due diversi attori. Il motivo di ciò è che una modifica al
comportamento di un attore non deve influire anche sugli altri attori. Esistono delle eccezioni a questa regola, ad
esempio per pacchetti che costituiscono dei servizi opzionali. I pacchetti di questo tipo non devono essere divisi, a
prescindere dal numero di attori che li utilizza. Quindi, suddividere qualsiasi pacchetto o classe utilizzati da
diversi attori, a meno che non si tratti di un pacchetto opzionale.
Tutte le classi dello stesso pacchetto devono essere funzionalmente correlate. Se sono stati seguiti i criteri della
sezione "Ricerca di pacchetti da classi funzionalmente correlate", le classi contenute in un pacchetto saranno
funzionalmente correlate fra loro. Tuttavia, una particolare classe potrebbe essa stessa contenere "troppa"
funzionalità o troppe relazioni che non appartengono alla classe. Parte della classe deve allora essere rimossa e
diventare una classe completamente nuova oppure deve essere spostata in qualche altra classe, che probabilmente
appartiene ad un altro pacchetto.
Esempio
La funzionalità di una classe di controllo A in un pacchetto non deve dipendere troppo da una classe B di
un altro pacchetto. Per isolare la funzionalità specifica di B, la classe di controllo A deve dividersi
in due classi di controllo A' e A". La funzionalità specifica di B viene collocata nella nuova
classe di controllo A", che viene messa nello stesso pacchetto di B. Anche la nuova classe A"
ottiene una relazione, come la generalizzazione, all'oggetto originale A'.
Per isolare la funzionalità specifica di B, la classe di controllo A, che manca di omogeneità, viene
suddivisa in due classi di controllo, A' e A''.
Se una classe di un pacchetto è associata ad una classe di un pacchetto diverso, i pacchetti dipenderanno l'uno
dall'altro. Le dipendenze dei pacchetti vengono modellate utilizzando una relazione di dipendenza fra i pacchetti. Le
relazioni di dipendenza sono utili per valutare le conseguenze delle modifiche: un pacchetto da cui dipendono molti
altri pacchetti è più difficile da modificare di uno da cui non ne dipende nessuno.
Poiché durante la specifica dei pacchetti verranno rilevate diverse dipendenze come questa, le relazioni vengono
collegate alla modifica durante il lavoro. La descrizione di una relazione di dipendenza può includere le informazioni
relative a quali relazioni di classe hanno causato la dipendenza. Poiché questo introduce delle informazioni difficili
da gestire, deve essere fatto solo se l'informazione è pertinente e di valore.
Esempio
In Sistema di gestione magazzino esiste una relazione di dipendenza fra il pacchetto Gestione dell'ordine
ed il pacchetto Gestione dell'articolo. Questa associazione si verifica perché la classe di entità Ordine
in Gestione dell'ordine ha un'associazione con la classe di entità Tipo di articolo nell'altro pacchetto.
Il pacchetto Gestione dell'ordine dipende da Gestione articolo, poiché esiste un'associazione fra due
classi dei pacchetti.
La dipendenza dei pacchetti è una cosa buona e cattiva: buona perché rappresenta il riutilizzo e cattiva perché
rappresenta le dipendenze che rendono il sistema più difficile da modificare e da evolvere. Si possono seguire alcuni
principi generali:
-
I pacchetti non devono essere dipendenti a incrocio (co-dipendenti); per esempio due pacchetti non devono essere
dipendenti uno dall'altro.
In questi casi, i pacchetti devono essere riorganizzati per rimuovere le dipendenze incrociate.
-
I pacchetti dei livelli inferiori non devono essere dipendenti dai pacchetti dei livelli superiori. I pacchetti
devono essere dipendenti solo da pacchetti dello stesso livello e nel successivo livello inferiore.
In questi casi la funzionalità deve essere risuddivisa. Una soluzione deve asserire le dipendenze in termini di
interfaccia ed organizzare le interfacce nel livello inferiore.
-
In generale, le dipendenze devono ignorare i livelli, a meno che il comportamento dipendente sia comune in tutti i
livelli, e l'alternativa è di passare semplicemente i richiami di operazioni nei livelli.
-
I pacchetti non devono dipendere dai sottosistemi, solo da altri pacchetti o da interfacce.
|