Olio-ohjelmointi
UML-luokkakaavion perusteet

UML eli Unified Modeling Language on standardoitu mallinnuskieli, jolla voidaan kuvata ohjelmistojen rakennetta ja toimintaa. Tässä oppaassa keskitytään luokkakaavioon, joka kuvaa luokat ja niiden väliset suhteet.

Luokka piirretään suorakaiteena, joka on jaettu kolmeen osaan: luokan nimi, attribuutit (jäsenmuuttujat) ja operaatiot (jäsenfunktiot). Kaikkia tietoja ei tarvitse näyttää jokaisessa kaaviossa, vaan mukaan valitaan kuvattavan asian kannalta olennaiset tiedot.

Luokkakaavion kolme osaa: luokan nimi, attribuutit ja operaatiot

Luokan jäsenten suojaustasoa kuvaavat symbolit ovat:

  • -: private eli yksityinen
  • +: public eli julkinen
  • #: protected eli suojattu

Esimerkiksi attribuutti -age: int tarkoittaa yksityistä int-tyyppistä jäsenmuuttujaa nimeltä age. Operaatio +getInfo(value: int): float tarkoittaa julkista jäsenfunktiota, joka ottaa int-tyyppisen parametrin ja palauttaa float-tyyppisen arvon.

Luokkien väliset yhteydet UML:ssä

Luokkien väliset suhteet esitetään viivoilla ja niiden päissä olevilla merkeillä. Viivan päässä olevan kolmion tai vinoneliön sijainti kertoo, miten suhde luetaan.

YhteysMerkintä UML-kaaviossaMerkitys ja esimerkki
Periytyminen Yhtenäinen viiva, jonka päässä on ontto kolmio. Kolmio osoittaa kantaluokkaan. Aliluokka perii kantaluokan. Kun Student perii Person-luokan, kolmio on Person-luokan päässä.
Assosiaatio Assosiaatio piirretään yhtenäisenä viivana. Viivaan voidaan lisätä avoin nuolenkärki osoittamaan, kumpaan suuntaan yhteyttä voidaan käyttää. Ilman nuolta yhteyden käyttösuuntaa ei määritellä. Luokkien olioilla on yhteys toisiinsa, esimerkiksi Doctor hoitaa Patient-oliota.
Aggregaatio eli heikko kooste Yhtenäinen viiva, jonka päässä on ontto vinoneliö. Vinoneliö on kokonaisuuden päässä. Kuvaa kokonaisuuden ja osan suhdetta, jossa osat voivat olla olemassa itsenäisesti. Team koostuu Player-olioista; vinoneliö on Team-luokan päässä.
Kompositio eli vahva kooste Yhtenäinen viiva, jonka päässä on täytetty vinoneliö. Vinoneliö on omistavan kokonaisuuden päässä. Kokonaisuus omistaa osat, ja sen tuhoutuminen tuhoaa siihen kuuluvat osat. Esimerkissä Car omistaa Engine-olion; vinoneliö on Car-luokan päässä.

Viivan päihin voidaan lisätä lukumäärät: 1 tarkoittaa yhtä, 0..1 nollaa tai yhtä, * nollaa tai useampaa ja 1..* yhtä tai useampaa. Merkintä kertoo, kuinka monta kyseisen pään oliota voi liittyä yhteen vastakkaisen pään olioon.

Jäljempänä samat suhteet esitetään Mermaid-koodina ja siitä muodostettuina kaavioina.

UML-luokkakaavioita voidaan laatia graafisilla työkaluilla, kuten draw.iolla ja Lucidchartilla. Seuraavaksi tehdään kaaviot tekstimuotoisesti Mermaidilla.

Luokkakaavion tekeminen Mermaidilla

Mermaid on työkalu, jolla voi tuottaa kaavioita kirjoittamalla yksinkertaista tekstipohjaista kuvauskieltä. Se soveltuu hyvin Markdown-dokumentteihin: kaavion kuvaus kirjoitetaan muun tekstin joukkoon, ja Mermaid-tukea käyttävä esikatselin näyttää sen kaaviona.

Mermaid-kaavioita voi näyttää myös HTML-sivuilla JavaScript-kirjaston avulla, laatia selaimessa Mermaid Live Editorilla ja viedä kuviksi esimerkiksi dokumentteja tai esityksiä varten. Tässä oppaassa keskitytään UML-luokkakaavioiden tekemiseen Markdown-tiedostoissa. Lopussa on lyhyt esimerkki saman kaavion lisäämisestä HTML-sivulle.

Mitä kaavioita Mermaidilla voi tehdä?

  • Luokkakaavio (Class Diagram)
  • Sekvenssikaavio (Sequence Diagram)
  • Vuokaavio (Flowchart)
  • Tilakaavio (State Diagram)
  • Käyttäjäpolku (User Journey)
  • Arkkitehtuurikaaviot (C4, Architecture)

Tässä oppaassa keskitytään luokkakaavioihin.

Mermaidin hyödyt

  • Nopea: kaaviot syntyvät tekstistä ja ne on helppo versioida.
  • Yhteensopiva: toimii Mermaid-tukea käyttävissä Markdown-lukijoissa ja editoreissa.
  • Ylläpidettävä: muutokset onnistuvat ilman erillistä piirto-ohjelmaa.
Mermaid Markdown-tiedostossa

GitHub tunnistaa Markdown-tiedoston mermaid-koodilohkot ja näyttää niiden sisällön kaavioina automaattisesti. Myös Visual Studio Coden Markdown-esikatselu tukee Mermaid-kaavioita. Kaikkien Markdown-lukijoiden ominaisuuksiin Mermaid-tuki ei kuitenkaan kuulu, joten käytettävän työkalun tuki kannattaa tarkistaa.

Mermaid-koodilohko merkitään .md-tiedostoon seuraavasti:

```mermaid
classDiagram
    class Person
```

Miten se toimii?

  1. Kirjoita kaavion kuvaus Mermaid-kielellä Markdown-tiedostoon.
  2. Rajaa kuvaus mermaid-koodilohkolla.
  3. Avaa tiedosto Mermaid-tukea käyttävässä Markdown-esikatselussa.
  4. Esikatselin muodostaa kuvauksesta kaavion automaattisesti.
Luokkakaavion luonti

Kirjoitetaan seuraava koodi Markdown-tiedostoon:

```mermaid
classDiagram
    class Student {
        -string firstname
        +setFirstname(string fname) void
        +getFirstname() string
    }
```

Markdown-esikatselu näyttää koodin kaaviona:

classDiagram
    class Student {
        -string firstname
        +setFirstname(string fname) void
        +getFirstname() string
    }

Edellistä luokkakaaviota vastaavan luokan määritys C++-kielellä olisi seuraava:

#include <iostream>

class Student {
    private:
        std::string firstname;
    public:
        Student();
        void setFirstname(std::string fname);
        std::string getFirstname();
};

Mermaid-esimerkin string vastaa tässä C++:n std::string-tyyppiä. Näissä esimerkeissä käytetään Mermaidin oman ohjeen kirjoitusasua: attribuutin tyyppi on ennen nimeä, esimerkiksi -string firstname, ja metodin paluutyyppi on sulkujen jälkeen, esimerkiksi +getFirstname() string. Näihin koodimerkintöihin ei kirjoiteta kaksoispistettä. Mermaid lisää metodin paluutyypin eteen kaksoispisteen näkyvään kaavioon automaattisesti. Attribuutin kirjoitusasu eroaa edellä esitetystä UML-merkinnästä -firstname: string, mutta kuvaa samat tiedot.

Huom! Muodostimen voi jättää luokkakaaviosta pois, jos se ei ole kuvattavan asian kannalta olennainen. Esimerkiksi pelkkä oletusmuodostin voidaan jättää näyttämättä. Muodostimen puuttuminen kaaviosta ei tarkoita, ettei luokalla olisi muodostinta.

UML-luokkakaavion perusteella voidaan kirjoittaa luokan määrittely C++:n otsikkotiedostoon (.h). Vastaavasti otsikkotiedostossa olevan luokan määrittelyn perusteella voidaan laatia UML-luokkakaavio. Luokkakaavio kuvaa luokan rakenteen, mutta metodien toteutukset kirjoitetaan yleensä erilliseen .cpp-tiedostoon.

Esimerkkejä luokkakaavioista

Seuraavissa esimerkeissä 1–4 kuvataan vain assosiaation, aggregaation, komposition ja perinnän Mermaid-koodit. Siksi luokkien sisälle ei ole kirjoitettu niiden attribuutteja ja metodeja, vaikka ne kuuluisivat luokkien täydellisiin kuvauksiin. UML-kaaviossa näitä tietoja voi jättää pois, kun halutaan keskittyä luokkien välisiin suhteisiin.

Esimerkki 1: assosiaatio

Koodi:

```mermaid
classDiagram
    class Doctor {

    }
    class Patient {

    }
    Doctor "1" -- "*" Patient : diagnose
```

Kaavio:

classDiagram
    class Doctor {

    }
    class Patient {

    }
    Doctor "1" -- "*" Patient : diagnose

Lukumäärämerkintä 1 tarkoittaa yhtä ja * nollaa tai useampaa. Tässä yksinkertaistetussa mallissa yhdellä lääkärillä voi olla useita potilaita ja jokaisella potilaalla on yksi lääkäri.

Esimerkki 2: aggregaatio

Koodi:

```mermaid
classDiagram
    class Team {

    }
    class Player {

    }
    Team "1" o-- "*" Player : has
```

Kaavio:

classDiagram
    class Team {

    }
    class Player {

    }
    Team "1" o-- "*" Player : has

Esimerkki 3: kompositio

Koodi:

```mermaid
classDiagram
    class Car {

    }
    class Engine {

    }
    Car *-- Engine : contains
```

Kaavio:

classDiagram
    class Car {

    }
    class Engine {

    }
    Car *-- Engine : contains

Esimerkki 4: perintä

Koodi:

```mermaid
classDiagram
    class Person {

    }
    class Student {

    }
    Person <|-- Student
```

Kaavio:

classDiagram
    class Person {

    }
    class Student {

    }
    Person <|-- Student

Esimerkki 5: perintä ja kooste

Tässä esimerkissä Classroom sisältää Student- ja Teacher-oliot arvojäseninä. Kompositio (*--) kuvaa sitä, että näiden jäsenolioiden elinkaari on sidottu Classroom-olioon. Jos mallinnetaan luokkatilasta riippumatta olemassa olevia opiskelijoita ja opettajia, suhde olisi yleensä assosiaatio.

Koodi:

```mermaid
classDiagram
    class Person {
        -int age
        -string name
        +Person()
        +getAge() int
        +getName() string
        +setAge(int) void
        +setName(string) void
    }
    class Student {
        -string groupName
        +Student()
        +getGroupName() string
        +setGroupName(string) void
    }
    class Teacher {
        -string department
        +Teacher()
        +getDepartment() string
        +setDepartment(string) void
    }
    class Classroom {
        -Student objectStudent1
        -Student objectStudent2
        -Teacher objectTeacher
        -string classRoomName
        +Classroom()
        +getClassRoomName() string
        +setClassRoomName(string) void
        +setClassRoomPersons() void
        +showClassRoomData() void
    }
    Person <|-- Student
    Person <|-- Teacher
    Classroom *-- Student : contains
    Classroom *-- Teacher : contains
```

Kaavio:

classDiagram
    class Person {
        -int age
        -string name
        +Person()
        +getAge() int
        +getName() string
        +setAge(int) void
        +setName(string) void
    }
    class Student {
        -string groupName
        +Student()
        +getGroupName() string
        +setGroupName(string) void
    }
    class Teacher {
        -string department
        +Teacher()
        +getDepartment() string
        +setDepartment(string) void
    }
    class Classroom {
        -Student objectStudent1
        -Student objectStudent2
        -Teacher objectTeacher
        -string classRoomName
        +Classroom()
        +getClassRoomName() string
        +setClassRoomName(string) void
        +setClassRoomPersons() void
        +showClassRoomData() void
    }
    Person <|-- Student
    Person <|-- Teacher
    Classroom *-- Student : contains
    Classroom *-- Teacher : contains
Mermaid-kaaviot HTML-sivulle

Mermaid-kaavioita voi näyttää myös HTML-sivulla. Tällöin sivulle lisätään kaavion kuvaus <pre class="mermaid">-elementin sisään ja ladataan Mermaidin JavaScript-kirjasto. Selain suorittaa JavaScriptin ja muuntaa kuvauksen SVG-kaavioksi.

<pre class="mermaid">
classDiagram
    class Student {
        -string firstname
        +setFirstname(string fname) void
        +getFirstname() string
    }
</pre>

<script type="module">
    import mermaid from
        'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
    mermaid.initialize({ startOnLoad: true });
</script>



Toggle Menu