Czym jest generalizacja#

Generalizacja (generalization) jest relacją między klasyfikatorami, która wskazuje, że element bardziej szczegółowy jest rodzajem elementu ogólniejszego. W diagramie klas linia kończy się pustym trójkątem skierowanym do klasy ogólnej. Relację można odczytać jako „Konto oszczędnościowe jest rodzajem Konta”.

Klasa bardziej szczegółowa dziedziczy cechy klasy ogólnej zgodnie z modelem i może dodawać własne właściwości lub zachowanie. W terminologii obiektowej często mówi się o nadklasie i podklasie, typie bazowym i podtypie oraz dziedziczeniu. UML opisuje relację modelową; język programowania może realizować ją własnym mechanizmem.

Notacja#

Klasy Konto oszczędnościowe i Konto firmowe dziedziczą po klasie Konto; pusty trójkąt jest skierowany do klasy ogólnej.
Generalizacja dwóch wyspecjalizowanych typów konta do klasy Konto.

Grot pustego trójkąta znajduje się po stronie klasy ogólnej. Obie klasy szczegółowe dzielą cechy i kontrakt Konta, a jednocześnie mogą wprowadzać własne reguły. Nazwa podtypu powinna oznaczać rzeczywistą specjalizację, nie przypadkową kategorię.

Dziedziczenie cech i kontrakt#

Model może umieścić wspólne atrybuty i operacje w klasie ogólnej, a różnice w podtypach. Na przykład każde konto ma numer i właściciela, ale konto oszczędnościowe może mieć regułę naliczania odsetek, a firmowe — reprezentować organizację.

Sama możliwość odziedziczenia pól nie uzasadnia hierarchii. Podtyp powinien zachowywać oczekiwane znaczenie typu ogólnego w kontekstach, w których jest używany. Jeśli operacja poprawna dla każdego Konta nie ma sensu dla KontaFirmowego, wspólny kontrakt może być źle zdefiniowany.

Generalizacja może obejmować ograniczenia kompletności i rozłączności zbioru podtypów. Kompletność określa, czy wymieniono wszystkie specjalizacje w danym modelu; rozłączność — czy instancja może należeć do kilku podtypów naraz. Zapisz takie ograniczenia, gdy wpływają na interpretację; sam zestaw linii nie zawsze czyni je oczywistymi.

Różnice względem innych relacji#

Generalizacja oznacza „jest rodzajem” i klasyfikację instancji. Kompozycja oznacza „jest częścią”; zależność — korzystanie jednego elementu z drugiego; realizacja — spełnienie kontraktu, np. implementację interfejsu. Nie zastępuj nimi dziedziczenia ani nie stosuj dziedziczenia, gdy model opisuje jedynie delegowanie odpowiedzialności.

W programowaniu dziedziczenie może łączyć podtyp i implementację, ale diagram UML nie jest automatycznie schematem klas konkretnego języka. Ograniczenia językowe dotyczące klas wielodziedziczenia, interfejsów czy metod trzeba odwzorować osobno.

Kiedy generalizacja pomaga#

Użyj jej, gdy istnieje stabilna wspólna kategoria, podtypy zachowują kontrakt ogólny, a odbiorcy potrzebują widzieć wspólne i specyficzne cechy. Przykładami mogą być hierarchie ról, rodzaje dokumentów lub odmiany urządzeń, jeśli różnice mają znaczenie dla modelu.

Jeśli różne warianty mają tylko wspólne pola, ale nie powinny być używane zamiennie, rozważ asocjację do wspólnego pojęcia, kompozycję, interfejs albo osobne typy. Jeśli wariantów może być wiele i zmieniają się często, hierarchia klas może być sztywna; cecha, strategia lub konfiguracja mogą lepiej opisywać różnice w projekcie.

Typowe błędy#

  • Odwrócony trójkąt. Grot wskazuje klasę ogólniejszą.
  • Dziedziczenie jako sposób unikania duplikacji. Wspólne pola nie wystarczają do uzasadnienia relacji typu.
  • Podtyp nie spełnia kontraktu. Operacje klasy bazowej przestają mieć sens dla specjalizacji.
  • Generalizacja mylona z kompozycją. „Jest rodzajem” różni się od „jest częścią”.
  • Hierarchia za głęboka. Wiele poziomów utrudnia ustalenie odpowiedzialności i zachowania.
  • Podtypy będące stanami. Stan KontoZablokowane może być stanem konta, a nie osobną klasą podtypu.
  • Nieokreślone podtypy. Odbiorca nie wie, czy lista specjalizacji jest kompletna lub rozłączna.
  • Utożsamienie modelu z kodem. Notacja nie narzuca jednego sposobu implementacji w języku.

Podsumowanie#

Generalizacja opisuje klasyfikację od typu szczegółowego do ogólnego i pozwala modelować wspólne cechy oraz specjalizacje. Pusty trójkąt skieruj do klasy bazowej. Stosuj relację, gdy podtyp rzeczywiście zachowuje kontrakt typu ogólnego, a nie tylko dzieli z nim część pól.