print
A A A

Dziedziczenie

Dziedziczenie jest relacją między klasami, zachodzącą wtedy gdy jakaś klasa (klasa pochodna) korzysta w swej definicji z definicji innej klasy (klasy bazowej, podstawowej)‏. Można wyobrażać sobie, że obiekty klasy pochodnej zawierają w sobie elementy klasy podstawowej.

Podstawowe rozróżnienie rodzajów dziedziczenia:

  • interfejsu – dziedziczonymi elementami są wyłącznie sygnatury funkcji składowych klasy
  • interfejsu i implementacji – dziedziczone są dane składowe (stan), sygnatury i implementacja metod
  • implementacji (nie zalecane) – dziedziczone jest wszystko jak wyżej, ale klientom na zewnątrz nie udostępnia się ani danych składowych (dobrze), ani funkcji składowych z interfejsu (kontrowersyjne)‏

W niektórych językach rozróżnienie dziedziczenia interfejsu i implementacji jest jawnie zapisywane w kodzie.

Kiedy, mając pewną klasę warto próbować dokonać specjalizacji i stworzyć podklasy?

  • gdy pojawiają się różniące się metodami rodzaje obiektów i wystarczająco duża liczba metod jest inna dla wyróżnionych rodzajów (podklas)‏
  • gdy specjalizacja umożliwi ponowne użycie klasy bazowej w innych kontekstach (klasa bazowa uwolniona od pewnych konkretów, przejdzie na wyższy poziom abstrakcji)‏

Klasa pochodna powinna wnosić co najmniej jedną z poniższych zmian:

  • nowe dane lub funkcje składowe
  • redefinicja istniejących funkcji składowych (redefinicja może oznaczać dodanie implementacji lub zmianę widzialności metody)‏
  • zmiana niezmienników klasy

Kiedy stosować dziedziczenie?

Dziedziczenie jest podobne do składania obiektów, należy je stosować wtedy gdy:

  • chcemy używać obiektów klas pochodnych, dla których typ określać będzie klasa podstawowa (np. będziemy posługiwać się wskaźnikiem do obiektu typu klasy podstawowej)‏
  • chcemy wprowadzić nową klasę, która częściowo modyfikuje zachowanie lub własności innej klasy, przy czym większość atrybutów i funkcji starej klasy pozostaje bez zmian (zwłaszcza jeśli chcemy pozostawić możliwość stosowania starej klasy)
  • nie spodziewamy się, aby obiekt klasy pochodnej miał kiedykolwiek w trakcie swojego istnienia dokonać zmiany atrybutów i zachowania związanych z klasą podstawową (w przeciwnym przypadku – gdy spodziewamy się wymiany składowych związanych z klasą podstawową na inne składowe – należy użyć bardziej elastycznej kompozycji obiektów)

Ważnym przypadkiem dziedziczenia jest sytuacja kiedy klasa podstawowa definiuje pewną istotną cechę lub zachowanie, natomiast klasa pochodna ma reprezentować zbiór obiektów wyposażonych w daną cechę lub zachowanie (przykłady z Javy: Serializable, Observable itp.). Ten typ dziedziczenia jest typowy dla dziedziczenia interfejsu: klasa podstawowa (abstrakcyjna) definiuje wymagane zachowanie, a klasa pochodna dostarcza odpowiednią dla obiektów tej klasy implementację zachowania.

«Identyfikacja klas     Weryfikacja hierarchii klas»