Relacja musi wyrażać znaczenie#

Relacja między klasami UML powinna opisywać istotny związek między typami obiektów, a nie jedynie upiększać diagram. Zanim wybierzesz symbol, nazwij związek zdaniem i sprawdź go na konkretnych instancjach: „klient składa zamówienia”, „zamówienie zawiera pozycje”, „pozycja dotyczy produktu”. To ujawnia kierunek, role, ograniczenia liczności i ewentualne zależności cyklu życia.

Rodzaj relacji ma znaczenie semantyczne. Asocjacja modeluje strukturalne powiązanie, uogólnienie — dziedziczenie klasyfikacyjne, a zależność — sytuację, w której element korzysta z innego. Agregacja i kompozycja są szczególnymi rodzajami asocjacji o semantyce całość–część. Nie wybieraj symbolu wyłącznie na podstawie tego, jak dane są zapisane w kodzie.

Asocjacja#

Asocjacja (association) wskazuje, że instancje jednej klasy mogą pozostawać w powiązaniu z instancjami drugiej. Linia może mieć nazwę, końce asocjacji mogą mieć nazwy ról i liczności, a nawigowalność może określać, w którą stronę model ujawnia dostęp do powiązanych obiektów.

Nazwę czytaj od początku do końca, a role interpretuj z perspektywy klasy przy przeciwległym końcu. Na przykład relacja Klient składa Zamówienia wskazuje, że po stronie zamówienia klient odgrywa rolę składający, a po stronie klienta powiązane obiekty to zamówienia. Nazwy pomagają rozumieć relację także wtedy, gdy diagram zawiera wiele linii.

Nie każda semantyczna relacja wymaga asocjacji. Jeśli klasa jedynie używa innej w trakcie operacji, zależność może lepiej oddać intencję. Jeśli pojęcia są współdzieloną własnością typu wartości lub kompozycją części, zwykła asocjacja może być zbyt ogólna.

Liczności#

Liczność (multiplicity) przy końcu asocjacji określa, ile instancji tego końca może być powiązanych z jedną instancją po przeciwnej stronie. Typowe zapisy:

ZapisZnaczenie
1Dokładnie jedna instancja
0..1Zero lub jedna instancja
* lub 0..*Dowolna liczba, także zero
1..*Co najmniej jedna instancja
2..5Od dwóch do pięciu instancji włącznie

Interpretuj liczność z perspektywy pojedynczego obiektu po przeciwnej stronie. Jeśli przy końcu Zamówienie widnieje 0..*, klient może być powiązany z wieloma zamówieniami. Jeśli przy końcu Klient widnieje 1, każde modelowane zamówienie ma dokładnie jednego klienta.

Liczności należy wyprowadzać z reguł, nie z pojedynczego przykładu ani obecnego schematu bazy. Ustal, czy odnoszą się do każdego stanu obiektu, tylko do poprawnego stanu końcowego, czy do określonego kontekstu. Jeżeli liczba zależy od warunku, zakresu czasu lub statusu, może być potrzebne dodatkowe ograniczenie.

Role, nazwy i nawigowalność#

Nazwa roli na końcu asocjacji objaśnia, jak powiązane obiekty są widziane z drugiej strony. Jest szczególnie pomocna przy relacjach samych klas ze sobą, kilku połączeniach tych samych typów lub gdy ogólna nazwa relacji jest niewystarczająca.

Nawigowalność pokazuje, czy model wskazuje dostęp od instancji jednej klasy do powiązanych instancji drugiej. Strzałka nie oznacza automatycznie przepływu procesu ani kierunku komunikatu. W wielu diagramach nawigowalność bywa pomijana, gdy nie jest istotna dla pytania, które model ma wyjaśnić.

Uogólnienie#

Uogólnienie (generalization) wyraża relację klasyfikacji: instancje klasy bardziej szczegółowej są również instancjami klasy ogólniejszej i dziedziczą jej cechy zgodnie z semantyką UML. Linia zakończona pustym trójkątem wskazuje klasę bazową.

Twórz hierarchię tylko wtedy, gdy podtyp naprawdę spełnia kontrakt typu bazowego i różnica ma znaczenie dla modelu. Wspólny zestaw pól sam nie wystarcza. Jeśli dwa pojęcia różnią się rolą, cyklem życia lub regułami, kompozycja, asocjacja, interfejs albo odrębne klasy mogą lepiej wyrazić ich związek.

Zależność#

Zależność (dependency) wskazuje, że jeden element korzysta z innego w sposób, który może sprawić, że zmiana dostawcy wpłynie na klienta. Zwykle przedstawia się ją linią przerywaną z otwartym grotem skierowanym do elementu, od którego zależymy. Szczegóły zależności mogą być określone stereotypem, np. użycia, jeśli jest to potrzebne.

Zależność jest słabsza i bardziej ogólna niż strukturalna asocjacja. Nie używaj jej jako uniwersalnej strzałki „coś ma związek z czymś”. Zdecyduj, czy chcesz pokazać trwałe powiązanie instancji, dziedziczenie, czy samo korzystanie.

Agregacja współdzielona i kompozycja#

Agregacja współdzielona (shared aggregation) oznaczana jest pustym rombem po stronie całości. Jej semantyka jest w UML celowo słaba i nie rozstrzyga szczegółowo własności ani cyklu życia części. Jeżeli pusty romb nie dodaje odbiorcy ważnej informacji, zwykła asocjacja bywa czytelniejsza.

Kompozycja (composite aggregation) oznaczana jest wypełnionym rombem przy całości. W UML część może należeć w danej chwili do co najwyżej jednej całości kompozytowej; kompozyt zarządza jej istnieniem i przechowywaniem w granicach semantyki tego powiązania. Nie sprowadzaj jej bezwarunkowo do „usunięcie rodzica zawsze kasuje dziecko” w każdym systemie — konkretne reguły i implementacja wymagają kontekstu.

Przykład zamówienia i pozycji jest często modelowany kompozycją, ponieważ pozycja zamówienia ma sens w kontekście danego zamówienia. Produkt katalogowy może być powiązany z wieloma pozycjami i istnieć niezależnie od pojedynczego zamówienia, więc nie jest częścią kompozycji zamówienia.

Klasa asocjacyjna#

Jeżeli samo powiązanie ma własne atrybuty lub zachowanie, rozważ klasę asocjacyjną (association class). Przykładowo powiązanie pracownika z projektem może mieć rolę, datę przydziału, wymiar zaangażowania i stawkę. Te dane dotyczą konkretnego przydziału, nie samego pracownika ani projektu.

Jeśli projekt potrzebuje tożsamości powiązania, wielu relacji między tymi samymi końcami albo niezależnego cyklu życia, zwykła klasa pośrednicząca połączona dwiema asocjacjami może być czytelniejsza. Wybór zależy od wymaganego znaczenia, nie tylko od możliwości notacji.

Przykład: zamówienie#

Diagram klas pokazuje klienta powiązanego z wieloma zamówieniami oraz zamówienie złożone z jednej lub wielu pozycji, z których każda dotyczy dokładnie jednego produktu.
Przykłady liczności, ról oraz kompozycji na modelu zamówienia.

Czytaj liczności przy obu końcach. Jeden klient może składać zero lub wiele zamówień, a każde zamówienie ma dokładnie jednego klienta. Jedno zamówienie zawiera co najmniej jedną pozycję; każda pozycja należy do jednego zamówienia. Wiele pozycji może dotyczyć tego samego produktu, a każda pozycja wskazuje dokładnie jeden produkt. Wypełniony romb przy Zamówienie wyraża kompozycję pozycji.

Przykład zakłada, że diagram opisuje poprawne, złożone zamówienia. Jeżeli system pozwala zachować szkic bez pozycji, trzeba doprecyzować, czy liczność ma dotyczyć także szkicu, czy tylko zamówień zatwierdzonych. Można wówczas zmienić model, opisać ograniczenie zależne od statusu albo rozdzielić pojęcia szkicu i złożonego zamówienia.

Wybór relacji — procedura#

  1. Zapisz znaczenie relacji zdaniem w języku dziedziny.
  2. Ustal, czy chodzi o trwałe strukturalne powiązanie, korzystanie, klasyfikację czy całość–część.
  3. Określ role i przeczytaj nazwę w obu kierunkach.
  4. Wyprowadź liczności z wymagań i przypadków granicznych.
  5. Zdecyduj, czy nawigowalność jest potrzebna w tym widoku.
  6. Rozważ agregację lub kompozycję tylko wtedy, gdy znaczenie całość–część wnosi informację.
  7. Sprawdź, czy relacja ma własne dane, które uzasadniają klasę asocjacyjną.
  8. Zweryfikuj model na konkretnych instancjach oraz w scenariuszach.

Typowe błędy#

  • Brak nazw relacji i ról. Czytelnik musi zgadywać, co oznacza linia.
  • Liczności wywnioskowane z bieżących danych. Modeluj regułę, nie przypadkowy stan produkcyjny.
  • Odwrócone odczytywanie końców. Liczność przy końcu opisuje liczbę obiektów tego końca dla jednego obiektu po przeciwnej stronie.
  • Strzałka użyta jako przepływ sterowania. Nawigowalność i komunikat nie są tym samym.
  • Dziedziczenie jako sposób współdzielenia pól. Podtyp musi być sensowną specjalizacją kontraktu.
  • Romb przy każdej relacji „ma”. Kompozycja ma semantykę własności części, a agregacja współdzielona jest słaba.
  • Założenie, że zwykła asocjacja jest dwukierunkowa. Opisz nawigowalność, jeśli to ważne.
  • Pominięcie warunków i ograniczeń. Sama liczność może nie wyrażać reguł zależnych od statusu lub czasu.
  • Atrybuty umieszczone po niewłaściwej stronie. Informacja o konkretnym powiązaniu może należeć do klasy asocjacyjnej.
  • Diagram zbyt gęsty. Podziel widok, jeśli liczba relacji utrudnia jego odczytanie.

Lista kontrolna#

  • Czy każda linia wyraża relację istotną dla celu modelu?
  • Czy nazwy i role jednoznacznie objaśniają znaczenie obu końców?
  • Czy liczności odpowiadają regułom, również dla stanów granicznych?
  • Czy asocjacja, zależność i uogólnienie zostały odróżnione?
  • Czy agregacja lub kompozycja dodaje uzasadnioną semantykę?
  • Czy dane relacji wymagają klasy asocjacyjnej?
  • Czy można odczytać diagram na przykładzie konkretnych obiektów?

Relacje są częścią znaczenia diagramu klas, a nie ozdobnikami. Nazywaj je, określaj role i liczności, a mocniejsze symbole stosuj wtedy, gdy ich semantyka rzeczywiście pomaga odbiorcy zrozumieć model.