Podręcznik
2. Związki pomiędzy obiektami
2.4. Kompozycja
W rzeczywistości, złożone obiekty często są budowane z mniejszych, prostszych obiektów. Na przykład samochód jest budowany z karoserii, silnika, czterech kół, skrzyni biegów, kierownicy, i jeszcze długo można by było wymieniać. Tak samo można powiedzieć o wielu wytworach techniki (toster zbudowany jest z obudowy, grzałek i mechanizmu wyrzutowego, smartfon ma CPU, pamięć, ekra, akumulator, itd...) czy biologii - człowiek ma głowę, tułów, serce, wątrobę, itd.... Taki typ relacji nazywa się kompozycją.
Mówiąc ogólnie, kompozycja obiektów modeluje relację "ma" pomiędzy dwoma obiektami. Samochód "ma" skrzynię biegów. Twój smartfon"ma" CPU, a człowiek "ma" serce (przynajmniej w sensie biologicznym). Złożony obiekt czasami jest nazywany całością. Prostszy obiekt jest często nazywany częścią lub składnikiem.
W C++ już widzieliście, że struktury i klasy mogą mieć składowe danych różnych typów (takich jak typy podstawowe lub inne klasy). Kiedy budujemy klasy które mają pola - to de facto konstruujemy złożony obiekt z prostszych części, co jest kompozycją. Z tego powodu, struktury i klasy są czasami nazywane typami złożonymi.
Kompozycja obiektów jest użyteczna w kontekście C++, ponieważ pozwala nam tworzyć złożone klasy, łącząc prostsze, łatwiej zarządzalne części. To redukuje złożoność i pozwala nam pisać kod szybciej i z mniejszą liczbą błędów, ponieważ możemy ponownie użyć kodu, który został już napisany, przetestowany i zweryfikowany jako działający.
Czasem występuje problem z rozróżnieniem agregacji i kompozycji. W obu przypadkach prawidłowe określenia to "należy do" czy też "ma" - więc na analizie leksykalnej nie możemy się w pełni oprzeć. Raczej powinniście sprawdzić dwa założenia:
- Składnik może należeć tylko do jednego obiektu jednocześnie.
- Czasem życia składnika zarządza obiekt nadrzędny.
Dobrym przykładem kompozycji w życiu codziennym jest relacja między człowiekiem a wątrobą. Dana wątroba może być tylko częścią jednego człowieka - nie można jej współdzielić. Nie powstała także sama z siebie - tylko wraz z człowiekiem, i z nim zginie.
Zauważcie, że kompozycja nie ma nic do powiedzenia na temat przenośności części. Wątroba może być przeszczepiane z jednego ciała do drugiego - jednak nawet po przeszczepieniu, nadal spełnia wymagania kompozycji (jest teraz własnością innego człowieka - ale ciągle funkcjonuje tylko jako jego część - a nie samodzielny byt).
Kompozycje w C++ implementuje się prosto i naturalnie - dając zwykłe pole w klasie. Kompozycje, które z wymagają dynamicznej alokacji / dealokacji pamięci (np składowa jest zbyt duża by mieścić się na stosie), mogą być implementowane przy użyciu wskaźników. W tym przypadku obiekt nadrzędny powinien być odpowiedzialny za wszystkie niezbędne wywołania new i delete (najlepiej zgodnie z RAII).
Kompozycja to częsty i preferowany związek. W ogólności - jeśli można zaprojektować klasę przy użyciu kompozycji, to powinna być tak zaprojektowana - pozwala to nie zaprzątać sobie głowy zarządzaniem czasem życia części składowych.