UML

Introduzione

UML (Unified Modeling Language) è un linguaggio di modeling il cui scopo è determinare uno standard comune nella rappresentazione visuale del software.

UML rappresenta in realtà una famiglia di formalismi, che si concretizzano nei concetti di diagrammi.

Class diagram

Concetto e struttura

Lo scopo del diagramma delle classi è fornire una vista statica del software (una sorta di “fotografia”) tramite la rappresentazione delle sue classi, corredate di metodi, attributi e relazioni.

I componenti identificabili in un diagramma delle classi sono:

  • oggetti (Classi e Interfacce), rispettivamente riconoscibili per le lettere “C” e “I” nella parte superiore di ogni blocco.

Esiste anche il marcatore "A", che rappresenta una classe astratta. Inoltre, per i diagrammi UML relativi a Java si può usare la lettera "E" per rappresentare le classi enum;

  • metodi: preceduti da un cerchio e dal tipo di valore ritornato;

  • attributi: preceduti da un quadrato, corrispondono agli attributi dell’oggetto;

  • relazioni: frecce che connettono gli oggetti.

È possibile rappresentare il cerchio dei metodi e il quadrato degli attributi con colori diversi in base alla visibilità. In Java, ad esempio, si può usare il verde per la visibilità public, l’arancio per protected e il rosso per private.

Valgono anche due regole sintattiche generali:

  • se una scritta è in corsivo vuol dire che all’elemento corrispondente manca qualche definizione ed è dunque da considerarsi astratto;
  • se una scritta è sottolineata vuol dire che l’elemento corrispondente (tipicamente metodo o attributo) è statico, ovvero ha una visibilità a livello di classe e non a livello di istanza (i.e è possibile riferircisi ad esso anche senza avere precedentemente istanziato la classe).

Relazioni

Nel diagramma delle classi UML esistono relazioni di diversi tipi. Ogni relazione viene rappresentata tramite una specifica forma di freccia:

  • frecce tratteggiate (associazione): sono le più generiche e indicano una relazione “gerarchica” tra classi. Ciò che c’è scritto nella classe da cui parte la freccia dipende dal codice che c’è nella classe a cui arriva la freccia (e.g. Deck dipende da Collections);

  • frecce con rombo bianco (aggregazione): indica che all’interno della classe (e.g. Deck) è presente una collezione (in questo caso una lista) di \(n\) oggetti (Card nell’esempio).
    Questa relazione non è più tra classi, bensì tra istanze delle classi (e.g. un’istanza di Deck aggrega da 0 a 52 carte);

  • frecce con rombo nero (composizione): è utilizzata quando si hanno degli elementi che sono fisicamente collegati tra loro (non solo virtualmente come nel caso delle carte).
    Senza l’uno l’altro non può vivere e viceversa.
    Un esempio può essere la rappresentazione del concetto di aereo: senza il motore l’aereo non può esistere, poichè il primo è un oggetto indispensabile per funzionamento del secondo. Specularmente, non accadrà mai che il motore passi ad un altro aereo (a differenza delle carte che possono passare a più mani).

  • frecce con la punta a triangolo (implementazione): una classe può implementare una classe astratta o un’interfaccia.

La direzione delle frecce è importante perché indica il senso della relazione.
Per esempio, il mazzo conosce le carte che contiene, ma le carte non conoscono i mazzi di cui fanno parte – è per questo che la direzione della freccia va da Deck a Card e non viceversa.

Sequence diagram

Concetto e struttura

Lo scopo del diagramma di sequenza è rappresentare il flusso di interazione tra attori all’interno di un software nel tempo. Di seguito ne è indicato un esempio.

Si compone di alcuni elementi chiave:

  • attori: rappresentano le entità coinvolte nel processo; spesso sono oggetti.
  • invocazioni: identificano chiamate di metodo su un attore da parte di un altro e sono rappresentate con una freccia che va da sinistra verso destra.
    La parte a sinistra è il chiamante e la parte a destra è il chiamato.
  • valori di ritorno: visualizzati tramite una freccia tratteggiata che va da destra verso sinistra.
  • cicli: aree rettangolari etichettate con il termine loop che specificano la presenza di un ciclo in una certa zona del diagramma.
  • condizioni: aree rettangolari etichettate con il termine opt che specificano la necessità di verificare alcune condizioni prima di entrare nella zona corrispondente.

State diagram

Concetto e struttura

L’obiettivo del diagramma di stato è fornire un’astrazione di comportamento significativa che sia comune all’intera classe.

La sua struttura deriva dai classici State Charts, dei quali costituisce un’ulteriore astrazione.

Al fine di comprendere meglio i diagrammi di stato, può essere utile ricordare che:

Negli State Charts, un automa è una sestupla \(\langle S, \, I, \, U; \; \delta, \, t, \, s_0 \rangle\).

  • \(S\): insieme finito e non vuoto degli stati;
  • \(I\): insieme finito dei possibili ingressi;
  • \(U\): insieme finito delle possibili uscite;
  • \(\delta\): funzione di transizione;
  • \(t\): funzione di uscita;
  • \(s_0\): stato iniziale.

Negli State Diagram, ogni stato è rappresentato da un rettangolo e lo stato iniziale è indicato da un pallino nero.

Nel diagramma le frecce possono avere diversi significati:

  • evento/azione: semplice e immediata transizione da uno stato ad un altro;
  • guardie: disambiguano le transazioni in uscita da uno stato che sono legate ad uno stesso evento;
  • time event: rappresentano eventi temporizzati.
    • After(duration): indicano un tempo massimo di permanenza nello stato destinazione.
      Allo scadere del timer, lo stato cambia.
  • change event: rappresentano eventi che si innescano al verificarsi di un cambiamento.
    • When(condition): indicano eventi espressi in termini di valori degli attributi.

Il verificarsi di eventi non esplicitamente marcati da un arco deve portare alla terminazione dell’esecuzione e al sollevamento di un errore.

Superstate

Ulteriore evoluzione dello State Diagram, il Superstate consente di rappresentare più facilmente una “gerarchia” di stati.

La transizione in uno stato può quindi condurre ad un’altra FSM concettualmente “innestata”.

Nel caso d’esempio, lo stato acceso possiede al suo interno un ulteriore diagramma di stato.

Ulteriori aggiunte

  • è possibile associare al diagramma uno stato history, il cui scopo è memorizzare lo stato storico prima dell’interruzione dell’FSM;
  • è possibile rendere il diagramma capace di rappresentare il concetto di concorrenza tramite la divisione in regioni (ognuna regolata da una propria FSM). Le regioni possono essere attive contemporaneamente. I confini tra regioni, come mostrato nell’esempio, sono identificati da linee tratteggiate.

Use cases diagram

Concetto e struttura

I diagrammi dei casi d’uso rappresentano l’astrazione di un insieme di scenari tra loro correlati.
Essi adottano un linguaggio che verte alla risoluzione di esigenze comunicative tramite un lessico potenzialmente meno tecnico. Tale natura “informale” li rende ottimi mezzi di comunicazione col cliente.

Possono essere utilizzati, ad esempio, per:

  • eplicitare differenti modalità di fare un compito;
  • stabilire quale dovrebbe essere la normale interazione nello scenario e le eccezioni che possono verificarsi.

Infatti, ogni scenario è corredato di:

  • pre e post condizioni da rispettare;
  • flusso di esecuzione da percorrere in condizioni normali;
  • eventuali eccezioni e loro possibili trattamenti.

Infine, parte della versatilità degli Use Case diagrams risiede nella loro capacità di collegarsi, eventualmente, ad altri tipi di diagrammi (Sequence, Activity, etc) che possono essere impiegati per descriverne in modo più approfondito il flusso.

Scenari

I componenti di ogni scenario si dividono in Attori e Casi d’Uso.

In generale il collegamento tra un attore e un caso d’uso rappresenta una relazione di partecipazione, i.e “Questo attore partecipa a questo caso d’uso”.

L’interazione può comunque essere denominata.

Sono contemplati anche collegamenti fra un caso d’uso e un altro (vedi paragrafo dedicato).

Identificazione degli attori

Gli attori non sono necessariamente persone fisiche. Possono corrispondere anche a dei ruoli o addirittura ad un sistema esterno.

Ogni attore è un’entità esterna al sistema ed interagisce direttamente con esso, fungendo allo stesso tempo da fonte e destinatario di informazione.

Ci sono due attori particolari:

  • attore beneficiario: colui che trae beneficio dall’interazione con lo use case, i.e. chi è interessato a quella funzionalità.
    Gli altri attori possono cambiare, ma il beneficiario rimmarrà probabilmente lo stesso;
  • attore primario: colui che avvia l’interazione con lo use case.

Identificazione use case

Il miglior modo di identificare i casi d’uso è interrogarsi su due fronti:

  • sistema: “quali funzionalità si desidera che il sistema possieda?”;
  • attori beneficiari: “cosa vogliono?”, “come agiscono?”, “perchè si interfacciano col sistema?” e “cosa si aspettano?”.

Associazioni

Ogni diagramma dei casi d’uso deve seguire due convenzioni per quanto riguarda le associazioni.

  • Ogni attore deve avere almeno un’interazione con un caso d’uso.

Un attore che non dovesse possedere alcuna associazione con un caso d’uso sarebbe impossibilitato a interagire col sistema e rappresentarlo nel diagramma non avrebbe alcun senso.

  • Ogni caso d’uso deve essere associato ad almeno un attore.

Un caso d’uso che non coinvolge alcun attore è un caso d’uso che, per definizione, non ha senso di esistere, poichè nessuno è in grado di interagirvi.

Relazioni use case - use case

Esistono due tipologie di relazioni tra use case:

  • inclusione (include): relazione che esprime il predicato “far parte di”.
    Chi include conosce sempre gli inclusi, ma non viceversa. La parte inclusa deve essere eseguita;
  • estensione (extend): relazione che viene utilizzata per rappresentare casi eccezionali che specificano comportamenti particolari in alcuni use case.

Generalizzazione

L’associazione di generalizzazione rappresenta un particolare tipo di relazione, applicabile sia ad una coppia attore - attore che ad una coppia use case - use case.

La sua semantica dipende dal contesto a cui viene applicata:

  • tra attori: permette di esplicitare eventuali relazioni tra ruoli.
    Ad esempio un ruolo potrebbe includerne un altro.
  • tra use case: la semantica è simile all’extend, ma senza punti d’estensione. Infatti, alcune parti della descrizione vengono ereditate e altre vengono sostituite. Non si applica il secondo principio della Liskov.

Esempi di utilizzo

Nel seguente diagramma,

l’attore Book Borrower è associato alle seguenti operazioni:

  • prendere in prestito un libro;
  • chiedere l’estensione del prestito di un libro.

In entrambi i casi, il bibliotecario deve controllare l’esistenza di una richiesta di prenotazione per il libro.

Il prossimo diagramma è differente:

rifiuta il prestito può essere l’estensione di un comportamento normale come prendi in prestito il libro. In quest’ultimo ci sono dei punti di estensione in cui vengono fatti dei controlli, come la verifica dello stato di prestito del libro o dell’identità del richiedente.

Activity diagram

Concetto e struttura

Gli activity diagram presentano una conformazione simile agli state diagram, ma con svariate differenze:

  • al posto degli stati vi sono le attività;
  • non si usano più le transizioni etichettate tramite eventi – queste sono quasi tutte implicitamente temporizzate;
  • possono esserci azioni dentro le attività;
  • le attività possono rappresentare elementi esterni al sistema.

La peculiare capacità di collegarsi con attività esterne fa sì che sia possibile utilizzare gli activity diagram come collante con e tra diversi casi d’uso.

Inoltre la visuale parzialmente informale, eppure leggermente più tecnica e profonda rispetto ai diagrammi dei casi d’uso, rende gli activity diagram un ottimo mezzo di comunicazione interna (e.g. con un manager).

Livelli di astrazione

Si possono utilizzare i diagrami delle attività per:

  • descrivere la logica interna di un business process (caso più comune);
  • descrivere il flusso interno di un metodo, con eventuali indicazioni di (pseudo)concorrenza;
  • dettagliare il flusso di un caso d’uso, ovvero chiarire meglio il suo flusso di esecuzione rispetto ad altri diagrammi (e.g. Sequence Diagram). Questa rappresentazione è assai utile nei casi in cui, ad esempio, la concorrenza è un fattore rilevante.

Sincronizzazione

Attraverso l’uso di barre si possono stabilire dei punti di sincronizzazione (JOIN).
I JOIN, se non diversamente specificato, vengono considerati in AND.

È però possibile porre dei vincoli diversi per stabilire i criteri di soddisficamento della barra di sincronizzazione (come una OR).

Decisioni

È possibile specificare nel flusso di esecuzione dei momenti di decisione. I corsi d’azione intraprendibili in questi frangenti sono rappresentati tramite degli archi.

Le decisioni devono rispettare due proprietà:

  • gli archi collegati alla decisione devono essere mutualmente esclusivi;
  • l’unione delle condizioni di decisione deve essere sempre vera.

È bene puntualizzare che i punti di decisione sono veri momenti di decisione umana, non banali valutazioni di una condizione logica.

Swim lane

Si può partizionare il diagramma al fine di rappresentare, sulle singole activity, delle particolari responsibilità. Queste vengono visualizzate tramite delle “corsie” verticali che identificano chi svolge una determinata attività.

Component diagram

Concetto e struttura

Lo scopo del diagramma dei componenti è rappresentare e raggruppare i componenti del sistema.
“Componente” è un termine trasversale che include file, librerie, documenti etc. (ma che è diverso dal concetto di classe!).

Il diagramma include:

  • componenti: rettangoli che rappresentano una funzione di sistema ben determinata.
    Possono essere annidati;
  • interfacce: cerchi che indicano le interfacce implementate o utilizzate dai componenti.
    I collegamenti con i componenti indicano la presenza di una dipendenza;
  • stereotipi: racchiusi tra i caratteri <<>>, etichettano e identificano una serie di funzionalità appartenenti ad uno stesso “gruppo”.

Si noti che un componente può usarne un altro conoscendone solo l’interfaccia.

Identificare i componenti

Alcune linee guida per identificare e rappresentare correttamente i componenti sono:

  • capire quali parti del sistema sono rimpiazzabili facilmente e/o sono versionate separatamente;
  • identificare quali parti del sistema svolgono una funzione ben determinata;
  • pensare in termini di “gerarchia” dei componenti;
  • chiarire l’esistenza di dipendenze con altri componenti e di dipendenze con le interfacce.

Deployment diagram

Il Deployment diagram permette di rappresentare la dislocazione fisica delle risorse.
Più precisamente, specifica la dislocazione fisica delle istanze dei componenti.

La conformazione del diagramma è quindi molto simile a quella del diagramma dei componenti, ma con qualche differenza:

  • i nodi del sistema indicano macchine fisiche;
  • i collegamenti tra nodi eplicitano le modalità di comunicazione tra gli stessi (e.g. RMI, HTTP).

Il Deployment diagram risulta di particolare utilità per il deployer, i.e. la figura che si occupa dell’installazione fisica del sistema.