Najpierw wybierz znaczenie, nie romb#

Agregacja i kompozycja są wariantami asocjacji w diagramie klas, używanymi do modelowania relacji całość–część. Agregację współdzieloną przedstawia pusty romb, a kompozycję (agregację kompozytową) — romb wypełniony. Kompozycja ma silniejsze konsekwencje dotyczące własności i cyklu życia części; agregacja współdzielona ma w UML słabo określoną semantykę i nie należy nadawać jej dodatkowych reguł bez jawnej konwencji.

Zespół agreguje Pracowników pustym rombem, a Zamówienie jest kompozytową całością swoich Pozycji oznaczoną wypełnionym rombem.
Kompozycja określa silniejszą własność i cykl życia części niż agregacja współdzielona.

Diagram ilustruje dwa różne zamysły. Zespół grupuje pracowników, którzy mogą istnieć niezależnie od zespołu. Pozycja zamówienia w tym modelu należy do jednej kompozytowej całości i jest częścią jej cyklu życia. W przykładzie trzeba jeszcze doprecyzować, czy pozycja może być tworzona przed zamówieniem, archiwizowana po jego usunięciu lub przenoszona — decyzje domenowe mogą zmienić relację.

Agregacja współdzielona#

Agregacja współdzielona (shared aggregation) to słabsza forma relacji całość–część, oznaczana pustym rombem po stronie agregatu, czyli całości. Sam romb nie określa dokładnie, czy część może być współdzielona, jak długo żyje ani co dzieje się z nią po usunięciu całości. Znaczenie tej relacji zależy od domenowej konwencji przyjętej przez modelujących.

Dlatego w wielu modelach zwykła asocjacja jest czytelniejsza niż pusty romb. Jeżeli chcesz powiedzieć jedynie „jest powiązany z”, użyj asocjacji. Jeśli chcesz wyrazić, że element jest częścią zbioru lub grupy, rozważ agregację tylko wtedy, gdy odbiorcy rozumieją, co dodatkowo oznacza w tym modelu.

Kompozycja#

Kompozycja (composite aggregation) jest silną relacją całość–część, oznaczaną wypełnionym rombem po stronie kompozytu. Część w danym czasie może należeć do najwyżej jednej całości kompozytowej. Kompozyt odpowiada za organizację części jako swojej struktury; usunięcie całości może skutkować usunięciem jej części, choć szczegółowe zachowanie systemu i trwałość danych należy określić w modelu domenowym.

Kompozycja nie wymaga, by część była technicznie przechowywana w polu obiektu całości, ani nie narzuca konkretnego mechanizmu pamięci. Dotyczy semantycznej własności modelu. Jeżeli część może swobodnie istnieć niezależnie, przechodzić między wieloma całościami lub być współdzielona bez ograniczeń, kompozycja będzie myląca.

Cykl życia nie sprowadza się do kaskadowego DELETE#

Często mówi się, że przy kompozycji część nie może istnieć po usunięciu całości. To użyteczna konsekwencja wielu modeli, ale nie należy automatycznie utożsamiać relacji z konkretną akcją SQL. UML określa własność kompozytową; system może zachowywać archiwalne dane, przenieść je do historii lub zastosować inną politykę, o ile model jasno określa znaczenie części i cyklu życia.

Zastanów się, czy część ma sens poza całością i czy jej tożsamość jest niezależna. Jeśli element zostaje zachowany po zamknięciu całości, zapytaj, czy nadal jest tą samą częścią, czy został przekształcony w osobny byt. Odpowiedź powinna wynikać z domeny, a nie wyłącznie z technicznej wygody kaskadowego usuwania.

Wybór relacji krok po kroku#

  1. Czy relacja opisuje „składa się z” lub „należy do całości”? Jeśli nie, użyj zwykłej asocjacji albo innego rodzaju relacji.
  2. Czy część może należeć w tej samej chwili do więcej niż jednej całości? Jeśli tak, kompozycja zwykle nie pasuje.
  3. Czy część ma własny cykl życia i może być używana samodzielnie? Jeśli tak, rozważ zwykłą asocjację.
  4. Czy ważne jest wyrażenie własności całości nad częścią? Jeśli tak, kompozycja może być właściwa.
  5. Czy potrzebujesz tylko słabego „grupuje/zawiera”, bez silnych konsekwencji? Pusty romb może być użyty zgodnie z lokalną konwencją albo zastąpiony zwykłą asocjacją.

Liczności opisują, ile części może należeć do całości i odwrotnie. Nie zastępują semantyki agregacji. Na przykład 1..* przy częściach mówi, że całość ma co najmniej jedną część w dopuszczalnych instancjach, a nie że relacja jest kompozycją.

Przykłady domenowe#

W zamówieniu pozycja opisuje element konkretnego zakupu, jego ilość i cenę z chwili zamówienia. Ponieważ nie jest po prostu globalnym produktem katalogu, kompozycja może pasować. Produkt katalogowy może być powiązany z wieloma pozycjami i istnieje niezależnie — zwykła asocjacja jest tu sensowniejsza.

W zespole pracownik może istnieć przed przypisaniem i po rozwiązaniu zespołu, a także zmieniać zespoły. Kompozycja byłaby nieuzasadniona; zwykła asocjacja lub ewentualnie jawnie zdefiniowana agregacja współdzielona lepiej oddaje relację. Wartości słowa „agregacja” w konkretnym projekcie mogą być różne, więc dodaj regułę, jeśli wybierasz pusty romb.

Typowe błędy#

  • Każda relacja „ma” zamieniona w kompozycję. Obecność atrybutu lub kolekcji nie dowodzi własności kompozytowej.
  • Agregacja uznana za silną kompozycję. Pusty romb nie niesie tych samych gwarancji cyklu życia.
  • Kompozycja użyta dla współdzielonej części. Jedna część nie może równocześnie należeć do wielu kompozytów.
  • Romb po stronie części. Oba rodzaje rombów znajdują się po stronie całości.
  • Kaskadowe kasowanie uznane za całą semantykę. Kompozycja dotyczy modelowanej własności i cyklu życia, nie konkretnego polecenia bazy.
  • Liczność potraktowana jak typ relacji. Liczba części i własność całości to różne informacje.
  • Pusty romb bez uzgodnionej interpretacji. Słaba agregacja wymaga jawnej, wspólnej konwencji albo zwykłej asocjacji.

Podsumowanie#

Kompozycja jest silną relacją własności całości nad częścią i oznacza część należącą w danym czasie najwyżej do jednej całości kompozytowej. Agregacja współdzielona ma znacznie słabszą, zależną od konwencji interpretację. Rysuj romb tylko wtedy, gdy wnosi jasne znaczenie względem zwykłej asocjacji.