Introduzione a UML

Introduzione a UML

  • Cos'è UML e a cosa serve
  • I principali tipi di diagramma
  • Il diagramma delle classi e le relazioni fra classi

Cos'è UML

  • UML = Unified Modeling Language
  • Linguaggio grafico standardizzato per descrivere sistemi software
  • Standardizzato da OMG (Object Management Group) dal 1997
  • La versione attuale è UML 2.5
  • Non è un linguaggio di programmazione: non si compila né si esegue
  • È un linguaggio di modellazione: serve a comunicare la struttura e il comportamento del sistema

Motivazioni

  • Un'immagine vale più di mille righe di codice: un diagramma mostra la struttura a colpo d'occhio
  • Lingua franca: permette a progettisti, sviluppatori e clienti di parlare della stessa cosa
  • Indipendente dal linguaggio di programmazione (C#, Java, C++, Python, …)
  • Utile in tutte le fasi: analisi, progettazione, documentazione
  • Aiuta a ragionare sul progetto prima di scrivere il codice

Storia in breve

  • Anni '80-'90: proliferazione di notazioni OO (Booch, OMT di Rumbaugh, OOSE di Jacobson, …)
  • 1994-1997: Booch, Rumbaugh, Jacobson uniscono le loro notazioni
  • 1997: UML 1.0 adottato da OMG come standard
  • 2005: UML 2.0, con una revisione profonda
  • Oggi UML 2.5 è lo standard de facto nell'industria e nella didattica OOP

Tipi di diagrammi

Due grandi famiglie

UML 2.5 definisce 14 tipi di diagrammi, organizzati in due famiglie:

Famiglia Cosa descrive Esempi
Strutturali Com'è fatto il sistema classi, oggetti, componenti
Comportamentali Come si comporta il sistema casi d'uso, sequenze, stati

Non è necessario usarli tutti: si scelgono quelli utili al problema che si sta descrivendo.

Diagrammi strutturali

  • Diagramma delle classi — classi, attributi, metodi, relazioni
  • Diagramma degli oggetti — istanze specifiche in un dato momento
  • Diagramma dei componenti — moduli software e loro interfacce
  • Diagramma di deployment — distribuzione su hardware/server
  • Diagramma dei package — raggruppamenti logici

Diagrammi comportamentali

  • Diagramma dei casi d'uso — cosa fa il sistema dal punto di vista dell'utente
  • Diagramma di sequenza — ordine temporale delle interazioni fra oggetti
  • Diagramma di attività — flusso di lavoro, simile a un flowchart
  • Diagramma di stato — stati di un oggetto e transizioni
  • Diagramma di comunicazione — messaggi scambiati fra oggetti

In questa presentazione ci concentreremo sul diagramma delle classi, che è il più usato nella progettazione OOP.

Il diagramma delle classi

Rappresentazione di una classe

Una classe è un rettangolo diviso in tre scomparti:

+---------------------------+
|          Auto             |   ← nome della classe
+---------------------------+
| - marca: string           |
| - velocitaMax: int        |   ← attributi (campi)
+---------------------------+
| + Avvia(): void           |
| + Ferma(): void           |   ← metodi (operazioni)
| + ToString(): string      |
+---------------------------+
  • Scomparto 1: nome della classe
  • Scomparto 2: attributi
  • Scomparto 3: operazioni (metodi)

Visibilità dei membri

Davanti a ciascun membro si mette un simbolo di visibilità:

Simbolo Significato Equivalente C#
+ public public
- private private
# protected protected

Sintassi di attributi e operazioni

Attributo:

visibilità nome : tipo [= valoreDefault]

Esempio: - velocitaMax: int = 0

Operazione:

visibilità nome(par1: tipo1, par2: tipo2): tipoRitorno

Esempio: + Somma(a: int, b: int): int

Se non c'è tipo di ritorno si omette

Convenzioni tipografiche

  • Nome della classe: centrato, in grassetto
  • Classe astratta: nome in corsivo, oppure stereotipo <<abstract>>
  • Metodo astratto: firma in corsivo

Esempio: classe con tutte le notazioni

+-----------------------------------+
|           /Veicolo/               |   ← astratta (corsivo)
+-----------------------------------+
| # marca: string                   |
| - _contatore: int                 |
+-----------------------------------+
| + Avvia(): void                   |
| + /Descrizione()/: string         |   ← astratto (corsivo)
+-----------------------------------+

Relazioni fra classi

Panoramica

Le classi non vivono isolate: sono collegate da relazioni. Le principali sono:

Relazione Simbolo UML "Senso"
Aggregazione rombo vuoto "ha un"
Composizione rombo pieno "è fatto di"
Generalizzazione freccia vuota "è un"

Aggregazione

  • Relazione "ha un" (has-a) debole
  • La parte può esistere anche senza il tutto
  • Simbolo: rombo vuoto dalla parte del "tutto"
Squadra ◇-------- Giocatore
   1               1..*

Se la Squadra viene sciolta, i Giocatore continuano a esistere.

Composizione

  • Relazione "è fatto di" (part-of) forte
  • La parte non può esistere senza il tutto: ciclo di vita condiviso
  • Simbolo: rombo pieno dalla parte del "tutto"
Libro ◆-------- Capitolo
  1              1..*

Se si distrugge il Libro, anche il Capitolo cessa di esistere.

Aggregazione vs Composizione

Aspetto Aggregazione (◇) Composizione (◆)
Ciclo di vita indipendente condiviso con il tutto
La parte esiste sola no
Esempio Università - Studente Casa - Stanza

Regola pratica: se la "parte" può essere condivisa o sopravvivere al "tutto", è aggregazione.

Generalizzazione (ereditarietà)

  • Relazione "è un" (is-a)
  • Corrisponde all'ereditarietà di OOP
  • Simbolo: freccia con punta triangolare vuota verso la classe base
       Veicolo
          △
          |
 +--------+--------+
 |                 |
Auto             Moto

Auto è un Veicolo; Moto è un Veicolo.

Esempio completo

Sistema "Biblioteca"

Modelliamo un piccolo sistema di gestione di una biblioteca:

  • Una Biblioteca è composta di Libro (composizione)
  • Una Biblioteca ha un insieme di Utente iscritti (aggregazione)
  • Esistono UtenteStandard e UtentePremium (ereditano da Utente)

In questo esempio compaiono solo le quattro relazioni viste: composizione, aggregazione, generalizzazione.

Diagramma delle classi (testo)

        /Utente/
        # nome: string
        + /TipoTariffa()/: string
              △
      +-------+-------+
      |               |
UtenteStandard   UtentePremium
+ TipoTariffa()  + TipoTariffa()


Biblioteca ◆------- Libro        Biblioteca ◇------- Utente
    1        1..*                     1         *
     (composizione)                     (aggregazione)

Le classi in forma tabellare

Classe Tipo Relazione con le altre
Utente astratta
UtenteStandard concreta eredita da Utente
UtentePremium concreta eredita da Utente
Biblioteca concreta composta di Libro, aggrega Utente
Libro concreta parte della Biblioteca (composizione)

Traduzione in C# (estratto)

abstract class Utente
{
    public int Id { get; }
    protected string nome;

    protected Utente(int id, string nome)
    {
        Id = id;
        this.nome = nome;
    }

    public abstract string TipoTariffa();
}

class UtentePremium : Utente
{
    public UtentePremium(int id, string nome) : base(id, nome) { }
    public override string TipoTariffa() => "Premium";
}
class Libro
{
    public string Titolo { get; }
    public Libro(string titolo) { Titolo = titolo; }
}

class Biblioteca
{
    // Composizione: i Libro nascono dentro la Biblioteca
    // e ne condividono il ciclo di vita
    private List<Libro> _libri = new List<Libro>();

    // Aggregazione: gli Utente esistono indipendentemente,
    // la Biblioteca si limita a "conoscerli" come iscritti
    private List<Utente> _iscritti = new List<Utente>();

    public void AggiungiLibro(string titolo)
        => _libri.Add(new Libro(titolo));

    public void Iscrivi(Utente u) => _iscritti.Add(u);
}

Altri diagrammi utili

Diagramma dei casi d'uso

  • Descrive cosa fa il sistema, dal punto di vista dell'utente
  • Attori (omini stilizzati) = ruoli che interagiscono con il sistema
  • Casi d'uso (ellissi) = funzionalità offerte
              +------------------+
              |   Biblioteca     |
              |                  |
 Utente ----( Cerca libro )      |
   \  \------( Prenota libro )   |
    \                            |
Bibliotecario --( Registra prestito )
              |                  |
              +------------------+

Diagramma di sequenza

  • Mostra l'ordine temporale dei messaggi fra oggetti
  • Il tempo scorre verso il basso; ogni oggetto ha una linea di vita verticale
:Utente       :UI        :Biblioteca     :Libro
   |           |              |             |
   |--cerca--->|              |             |
   |           |--trova------>|             |
   |           |              |--getInfo--->|
   |           |              |<--info------|
   |           |<--risultato--|             |
   |<-mostra---|              |             |

Diagramma di stato

  • Mostra gli stati possibili di un oggetto e le transizioni
  • Utile per oggetti con comportamento reattivo (es. un Prestito)
 [inizio]
    |
    v
Prenotato --richiedi--> Attivo --restituisci--> Concluso --> [fine]
                          |
                       scadenza
                          |
                          v
                       Scaduto

Strumenti

Come si disegnano i diagrammi UML

  • Lavagna / carta: il modo più rapido in fase di brainstorming
  • Editor grafici: draw.io (diagrams.net), Lucidchart, Visio, Dia
  • Textual UML:
    • PlantUML — diagrammi da testo, ottimo per la documentazione versionata in Git
    • Mermaid — supportato da molti strumenti moderni (GitHub, Notion, …)
  • IDE con supporto UML: Visual Studio, IntelliJ, Rider

Esempio PlantUML

@startuml
abstract class Utente {
    # nome: string
    + {abstract} TipoTariffa(): string
}

class UtenteStandard
class UtentePremium

Utente <|-- UtenteStandard
Utente <|-- UtentePremium

class Biblioteca
class Libro
Biblioteca "1" *-- "1..*" Libro : contiene
@enduml

Lo stesso diagramma si ottiene da poche righe di testo, versionabili con il codice.

Simboli principali

Elemento Notazione
Classe rettangolo a 3 scomparti
Classe astratta nome in corsivo
Membro public +
Membro private -
Membro protected #
Relazione Notazione
Associazione linea
Aggregazione rombo vuoto (lato del "tutto")
Composizione rombo pieno (lato del "tutto")
Generalizzazione freccia piena vuota verso la base

Consigli pratici

  • Non cercare di mettere tutto in un unico diagramma: meglio più diagrammi focalizzati
  • Disegnare prima di codificare: aiuta a scoprire i problemi quando costa poco correggerli
  • Usare UML come strumento di comunicazione, non come adempimento burocratico
  • Iniziare con il diagramma delle classi e il diagramma dei casi d'uso: coprono il 90% dei casi nella didattica OOP

Fine

Specifica ufficiale UML: https://www.omg.org/spec/UML/

PlantUML: https://plantuml.com/