Appendice. Notazione per gli statechart

 

Introduzione

In questa appendice descriviamo un particolare tipo di diagrammi, che si rivela molto utile per descrivere il dialogo fra utente e sistema. Si tratta degli statechart, inventati da David Harel nel 1987,[1] come strumento di modellazione di sistemi complessi, che abbiamo introdotto nel Capitolo 9. Gli statechart, con il nome di state machine diagrams, sono stati in seguito adottati da UML (Unified Modeling Language), il linguaggio visuale standardizzato usato nell’ingegneria del software, soprattutto per la progettazione di sistemi orientati agli oggetti.[2]

UML comprende numerose notazioni differenti, che possono essere selezionate in funzione delle esigenze e delle preferenze del progettista. Anche per descrivere l’interazione fra utente e sistema, UML propone diverse alternative. La scelta degli statechart non è quindi l’unica possibile. La proponiamo perché ci sembra quella che concilia semplicità e potenza descrittiva. In questo libro seguiamo la notazione adottata da UML 2.

Gli statechart sono diagrammi a stati di tipo gerarchico. In altre parole, la loro caratteristica principale è quella di permettere di modellare un sistema descrivendone la sua evoluzione da uno stato all’altro, per livelli di astrazione successivi. Questo è molto utile per descrivere con relativa semplicità situazioni che altrimenti richiederebbero diagrammi molto complessi dal punto di vista grafico. Essi possono essere utilizzati per rappresentare sistemi di vario tipo, e non necessariamente per descrivere i dialoghi fra utente e sistema.

Nel seguito, ci limiteremo a descrivere i costrutti di uso più frequente in modo piuttosto informale, rimandando il lettore che desiderasse informazioni più complete ai testi specialistici.[3]

Stati

In un diagramma per macchine a stati, uno stato del sistema modellato è rappresentato da un rettangolo con gli angoli arrotondati, con il nome dello stato al suo interno:

Figura 1.  Rappresentazione grafica di uno stato di nome A

Transizioni

Una transizione è rappresentata da un segmento orientato che connette fra loro due stati. Essa indica il passaggio da uno stato all’altro.

Una transizione è contrassegnata da una etichetta composta da tre parti, ciascuna delle quali è opzionale:

evento [condizione] /attività

 

evento                (detto anche trigger) indica l’evento che innesca la transizione da uno stato all’altro;

pre-condizione    (detta anche guard) indica una condizione booleana che deve essere verificata affinché la transizione abbia luogo;

attività              indica una azione che deve essere eseguita dal sistema durante la transizione.

 

Così, nel seguente diagramma, quando il sistema si trova nello stato A, al verificarsi dell’evento e si passa allo stato B effettuando l’azione A, purchè sia verificata la condizione c.

Figura 2.  Una transizione da A a B

Quando il sistema si trova in un certo stato e accade un determinato evento, si può verificare una sola transizione uscente da quello stato. Di conseguenza, quando ci sono più transizioni etichettate con lo stesso evento, le condizioni associate devono essere mutuamente esclusive. Questa situazione si può rappresentare anche utilizzando un rombo, che simboleggia una scelta, come in Figura 3.

Figura 3.  Il rombo rappresenta un’alternativa

 

Lo stato iniziale di un diagramma è quello indicato dalla (unica) transizione uscente da un pallino nero. Lo stato finale viene rappresentato invece da un pallino nero cerchiato.[4] Così, nel diagramma seguente, A è lo stato iniziale. Quando si verifica l’evento e, il sistema va nello stato finale.

Figura 4.  La notazione per indicare stato iniziale e stato finale

 

Allo scopo di semplificare il diagramma, più transizioni possono essere connesse attraverso giunzioni:

Figura 5.  Le giunzioni possono semplificare un diagramma

 

Il diagramma di Figura 6 descrive il funzionamento di una macchina erogatrice di bevande.

Figura 6.  Diagramma a stati che modella il funzionamento di una macchina erogatrice di bevande

Transizioni interne

A volte può essere utile poter indicare che il sistema modellato effettua delle attività (eventualmente subordinate al verificarsi di certi eventi e condizioni) senza cambiare stato. Queste situazioni possono essere rappresentate scrivendo eventi, condizioni e attività all’interno dello stato, con la stessa notazione vista in precedenza: evento[condizione]/attività.  In questo caso, il rettangolo arrotondato che rappresenta lo stato viene suddiviso in due sezioni, una per il nome e una per le altre informazioni.

Per esempio, in Figura 7 abbiamo raffinato l’esempio di Figura 6, indicando che l’erogatrice, nello stato Seleziona bevanda, è in grado di segnalare all’utente quali bevande sono esaurite. In questo esempio abbiamo anche utilizzato gli eventi speciali entry ed exit. Il primo si verifica automaticamente quando il sistema entra nello stato, e causa l’esecuzione dell’attività specificata (nel nostro caso: display “Seleziona bevanda”). Il secondo si verifica automaticamente immediatamente prima che il sistema esca dallo stato. L’attività specificata (nel nostro caso: display “Grazie!”) verrà eseguita dopo ogni altra attività associata allo stato.

Figura 7.  Uno stato con transizioni interne

 

Le attività interne permettono di modellare situazioni complesse senza che ciò comporti necessariamente  una eccessiva proliferazione di stati nel diagramma.

Stati composti

Uno stato composto (o superstato) è uno stato che può essere decomposto in una o più regioni, ciascuna delle quali può contenere altri stati (detti sottostati). Consideriamo, per il momento, stati composti da una sola regione.

La Figura 8 mostra uno stato A contenente una sola regione, la quale contiene una macchina a stati che specifica, ad un livello d’astrazione inferiore, il “comportamento interno” di A.

Figura 8.  A è uno stato composto, B e C sono suoi sottostati.

Quando il sistema entra nello stato composto A, esso entra nel sottostato B (che è lo stato iniziale del diagramma interno), per poi transitare nel sottostato C, e quindi terminare. Se A e B hanno attività associate agli eventi speciali entry, esse vengono eseguite (prima quella associata ad A, e subito dopo quella associata a B). Analogamente per gli eventi speciali exit associati a C e ad A: all’uscita, verrà prima eseguita l’azione relativa a C, e quindi quella relativa ad A.

 

Per non complicare troppo i diagrammi, i sottostati di uno stato composto possono venire specificati a parte. In questo caso, per indicare che uno stato è composto, si usa la notazione seguente:

Figura 9.  Il simbolo che indica che A è uno stato composto

Vediamo un esempio di stato composto. Nel diagramma di Figura 6 possiamo dettagliare a parte lo stato Inserisci monete, come inFigura 10. In tale diagramma, abbiamo supposto che tutte le bevande abbiano lo stesso prezzo e che lo stato Macchina spenta effettui, all’uscita, l’azzeramento di un contatore importo.[5]

Figura 10.       La descrizione dello stato composto Inserisci monete di Figura 108

 

Come si vede dall’esempio di Figura 11, il diagramma contenuto in uno stato composto non deve necessariamente possedere un solo punto di ingresso e un solo punto di uscita. Possiamo, infatti, definire altri pseudo-stati di ingresso e di uscita, usando la notazione indicata nella stessa figura.

 

 

 

 

 

 

Figura 11.       Pseudo-stati di ingresso e di uscita

Più pseudo-stati di ingresso e di uscita possono essere differenziati assegnando loro un nome. Il diagramma di Figura 11 può essere anche rappresentato come in Figura 12.

Figura 12.       Una rappresentazione alternativa dello stato composto di Figura 11

Sottomacchine

Può essere necessario richiamare uno stesso diagramma da varie parti di un diagramma di più alto livello. In tal caso, si dice che il diagramma richiamato rappresenta una sottomacchina del chiamante. Per esempio, nella Figura 13 una sottomacchina S è richiamata da due stati diversi. La notazione A:S si può leggere “lo stato A è una istanza della sottomacchina S”.

Figura 13.       Una sottomacchina S richiamata da più punti di un diagramma a stati di più alto livello

 

Notazioni abbreviate

Per permettere di rappresentare in modo semplice anche situazioni complesse, senza dover disegnare nel diagramma troppe transizioni, si possono definire alcune notazioni abbreviate. Per esempio, possiamo rendere più compatto un diagramma in cui lo stesso evento e conduce a uno stesso stato a partire da più stati diversi, come in Figura 14.

Figura 14.       Il diagramma (a) può essere rappresentato, in modo graficamente più semplifice, come in (b)

 

È anche possibile rendere più compatti quei diagrammi in cui da uno stesso stato si raggiungono più stati diversi, come in Figura 15 (a). In questo caso, si introduce la notazione di Figura 15 (b), che utilizza uno pseudo-stato selettore S. L’evento e è definito (nella nota accanto al diagramma) come la disgiunzione degli eventi e1 ed e2. Il selettore attiverà lo stato A quando e=e1, e lo stato B quando e=e2. Ovviamente, dovremo indicare con precisione la regola per associare ciascun evento a ciascuno stato di destinazione, come si è fatto in figura.

Figura 15.       Semplificazione di un diagramma attraverso la introduzione di un selettore S

La notazione precedente può essere generalizzata al caso in cui la selezione di uno stato fra più stati alternativi dipende dal valore di un parametro p, come in Figura 16. In questo caso, l’evento e(p) causa la transizione allo stato D(p).

Figura 16.       Attivazione di uno stato D(p) in funzione di un evento e(p), dipendente dal parametro p

 

Queste semplici convenzioni possono semplificare in modo significativo diagrammi complessi. Per esempio, il diagramma di Figura 17 (a) può essere rappresentato in forma compatta come in Figura 17 (b).

 

Figura 17.       Il diagramma (a) può essere rappresentato in forma più compatta come in (b), introducendo lo stato composto E.

Sottostati concorrenti

Finora abbiamo considerato stati composti costituiti da una sola regione. Quando le regioni sono più di una, gli stati contenuti in una regione sono concorrenti a quelli delle altre. Pertanto, lo stato composto si potrà trovare contemporaneamente in più sottostati, ciascuno appartenente ad una sua diversa regione.

Le regioni di uno stato sono separate da linee tratteggiate, orizzontali o verticali, come nellaFigura 18, che mostra uno stato composto da due regioni.

Con riferimento a questa figura, quando si entra nello stato composto A, vengono attivati contemporaneamente gli stati iniziali di tutte le regioni (nel nostro caso, B e D). I diagrammi di ogni regione poi evolvono in parallelo.

Quando tutti i diagrammi raggiungono il loro stato finale, allora termina anche lo stato composto e, nel caso, viene eseguita l’azione associata al suo evento speciale exit).

Figura 18.       Uno stato composto A costituito da due regioni

La Figura 19 mostra un semplice esempio di diagramma con stati concorrenti.  Esso rappresenta l’evoluzione della preparazione di un corso universitario. Per superare l’esame, occorre frequentare un laboratorio, realizzare un progetto di esame e sostenere con successo un compito scritto.

Figura 19.       Macchina a stati che rappresenta la preparazione di un corso universitario

 

<< Per Approfondire


[1] D.Harel, Statecharts: A visual formalism for complex systems, in Science of Computer Programming, vol.8, n.10, pagg.231-274, 1987, reperibile anche in rete.

[2] Per una introduzione a UML, si veda, per esempio, M.Fowler, UML distilled (Terza edizione). Ed. italiana: Pearson

– Addison Wesley, 2004.

 

[3] Tutti i libri su UML hanno un capitolo sui diagrammi per macchine a stati. Tuttavia, questi diagrammi vengono trattati spesso in modo sommario. Il riferimento più completo è quello ufficiale, costituito dalla specifica dell’OMG: Unified Modeling Language Superstructure – Version 2.0 (sezione 15), che si può trovare sul sito www.omg.org.

[4] Il pallino nero non rappresenta uno stato del sistema. Pertanto, la freccia che da esso esce non può avere associati eventi, condizioni o azioni. Il pallino nero cerchiato, invece, è uno stato a tutti gli effetti. Pertanto, la freccia in esso entrante può avere associati eventi, condizioni o azioni.

[5] Questo può essere specificato associando allo stato Macchina spenta una transizione interna del tipo: exit / azzera importo.