Związki pomiędzy klasami w UML

W projektowaniu oprogramowania, UML (Unified Modeling Language) jest niezastąpionym narzędziem do wizualizacji architektury systemu. Służą do przedstawienia struktury systemu poprzez modelowanie klas, ich atrybutów, metod oraz relacji pomiędzy nimi. Aby zrozumieć, jak tworzyć i interpretować te diagramy, omówmy ich główne składniki i sposób reprezentacji. Dziś omówimy różne rodzaje związków pomiędzy klasami w UML, używając przykładu implementacji w PHP, który obejmuje klasę bazową Vehicle oraz pochodne klasy Car, Truck, i Motorbike.

Podstawowe Składniki Diagramu Klas UML

  1. Klasy: Reprezentowane jako prostokąty podzielone na trzy sekcje: nazwa klasy, atrybuty (pola) i metody (funkcje). Nazwa klasy jest umieszczona w górnej sekcji, atrybuty w środkowej, a metody w dolnej.
  2. Związki: Linie łączące klasy reprezentują różne rodzaje relacji między nimi, takie jak asocjacje, dziedziczenie, agregacje, kompozycje i zależności.

Związki pomiędzy klasami

Zależność

Zależność (ang. dependency) jest najsłabszą relacją jaka może występować pomiędzy dwoma klasami. Zależność występuje, gdy jedna klasa wykorzystuje inną klasę do wykonania swojej funkcji, ale nie przechowuje jej jako stanu. Na przykład, jeśli klasa Vehicle używa klasy Engine do przeprowadzenia operacji start(), ale nie przechowuje Engine jako atrybutu.

class Engine {
    public function start() {
        echo "Silnik uruchomiony.";
    }
}

class Vehicle {
    public function startEngine(Engine $engine) {
        $engine->start();
    }
}

Powyższą zależność należy czytać w sposób: klasa Vehicle jest zależna od klasy Engine.

System powinien mieć jak najmniej zależności, jednak w miarę rozwoju projektu nie da się ich uniknąć. Aby pozbyć się zależności można jako parametr funkcji przekazać kilka typów prostych, zamiast jednej klasy. Spowoduje to zmniejszenie ilości zależności, jednak rodzi inne problemy (tzw. nadużywanie typów prostych (ang. primitive obsession)).

Asocjacja

Asocjacja odnosi się do związku, gdzie obiekty jednej klasy mogą być powiązane z obiektami innej klasy (np. jeden-do-wielu, wiele-do-wielu). Przykładem może być relacja między Vehicle a Driver, gdzie jeden pojazd może być prowadzony przez wielu kierowców.

class Driver {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }
}

class Vehicle {
    private $drivers = [];

    public function addDriver(Driver $driver) {
        $this->drivers[] = $driver;
    }
}

jest silniejszym rodzajem relacji niż zależność. Asocjacje mogą być jednokierunkowe, dwukierunkowe oraz nieokreślone (bez grotów na końcu linii). W diagramach klas UML asocjacji używa się bardzo często. Wynika to z faktu jej wysokiego poziomu abstrakcyjności.

Agregacja częściowa

Agregacja częściowa to związek typu całość-część, gdzie część (komponent) może istnieć niezależnie od całości. Na przykład, Car może mieć Wheels, ale koła mogą istnieć także poza samochodem.

class Wheel {
    public $size;
    
    public function __construct($size) {
        $this->size = $size;
    }
}

class Car extends Vehicle {
    private $wheels = [];

    public function addWheel(Wheel $wheel) {
        $this->wheels[] = $wheel;
    }
}

klasa Vehicle ma klasę Wheel.

Agregacja całkowita (kompozycja)

Kompozycja to bardziej rygorystyczna forma agregacji, gdzie części nie mogą istnieć niezależnie od całości. Przykładem może być relacja Engine w Vehicle, gdzie silnik nie istnieje bez pojazdu.

class Engine {
}

class Vehicle {
    private $engine;

    public function __construct() {
        $this->engine = new Engine(); // Engine jest integralną częścią Vehicle
    }
}

Jeżeli klasa główna tworzy jakiekolwiek referencje wewnątrz, to zawsze będzie to relacja agregacji całkowitej.

Dziedziczenie

Dziedziczenie to relacja, gdzie klasy pochodne dziedziczą atrybuty i metody klasy bazowej. W naszym przykładzie, Car, Truck, i Motorbike są pochodnymi klasy Vehicle.

class Vehicle {
    public $fuelType;

    public function __construct($fuelType) {
        $this->fuelType = $fuelType;
    }
}

class Car extends Vehicle {
}

class Truck extends Vehicle {
}

class Motorbike extends Vehicle {
}

Rozumienie różnych typów związków w UML umożliwia lepsze projektowanie i implementację systemów oprogramowania. Używając języka PHP jako przykładu, pokazaliśmy, jak można modelować różne związki pomiędzy klasami, co jest kluczowe dla tworzenia skalowalnych i łatwych w utrzymaniu aplikacji. W praktyce, te związki pomagają w zrozumieniu, jak obiekty współdziałają ze sobą w ramach większego systemu.

Moje początki programowania sięgają 2010r. W trakcie wielu projektów zdobywałem doświadczenie, rozwijając nie tylko umiejętności techniczne, ale także kompetencje miękkie. Programuje głównie w PHP i Python.