Nie jest kwestią tego, co jest najlepsze, ale kiedy z czego korzystać.
W „normalnych” przypadkach wystarczy proste pytanie, aby dowiedzieć się, czy potrzebujemy dziedziczenia czy agregacji.
- Jeśli nowa klasa jest mniej więcej taka, jak oryginalna klasa. Użyj dziedziczenia. Nowa klasa jest teraz podklasą oryginalnej klasy.
- Jeśli nowa klasa musi mieć klasę oryginalną. Użyj agregacji. Nowa klasa ma teraz klasę oryginalną jako składową.
Istnieje jednak duża szara strefa. Potrzebujemy więc kilku innych sztuczek.
- Jeśli korzystaliśmy z dziedziczenia (lub planujemy z niego korzystać), ale używamy tylko części interfejsu, lub jesteśmy zmuszeni nadpisać wiele funkcji, aby zachować logiczną korelację. Następnie mamy duży nieprzyjemny zapach, który wskazuje, że musieliśmy użyć agregacji.
- Jeśli korzystaliśmy z agregacji (lub planujemy z niej korzystać), ale okazuje się, że musimy skopiować prawie całą funkcjonalność. Następnie mamy zapach wskazujący na kierunek dziedziczenia.
Krótko mówiąc. Powinniśmy używać agregacji, jeśli część interfejsu nie jest używana lub musi zostać zmieniona, aby uniknąć nielogicznej sytuacji. Dziedziczenie jest potrzebne tylko wtedy, gdy potrzebujemy prawie całej funkcjonalności bez większych zmian. W razie wątpliwości użyj funkcji Agregacja.
Inną możliwością w przypadku, gdy mamy klasę, która potrzebuje części funkcjonalności oryginalnej klasy, jest podzielenie oryginalnej klasy na klasę główną i podklasę. I niech nowa klasa dziedziczy po klasie głównej. Należy jednak uważać, aby nie tworzyć nielogicznej separacji.
Dodajmy przykład. Mamy klasę „Pies” z metodami: „Zjedz”, „Spacer”, „Kora”, „Zabawa”.
class Dog
Eat;
Walk;
Bark;
Play;
end;
Potrzebujemy teraz klasy „Kot”, która wymaga „Jedz”, „Spacer”, „Mruczenie” i „Zabawa”. Więc najpierw spróbuj przedłużyć go z psa.
class Cat is Dog
Purr;
end;
Wygląda dobrze, ale czekaj. Ten kot może szczekać (miłośnicy kotów mnie za to zabiją). A szczekający kot narusza zasady wszechświata. Musimy więc zastąpić metodę Bark, aby nic nie robiła.
class Cat is Dog
Purr;
Bark = null;
end;
Ok, to działa, ale brzydko pachnie. Spróbujmy więc agregacji:
class Cat
has Dog;
Eat = Dog.Eat;
Walk = Dog.Walk;
Play = Dog.Play;
Purr;
end;
Ok, to jest miłe. Ten kot już nie szczeka, nawet milczy. Ale nadal ma wewnętrznego psa, który chce się wydostać. Wypróbujmy więc rozwiązanie numer trzy:
class Pet
Eat;
Walk;
Play;
end;
class Dog is Pet
Bark;
end;
class Cat is Pet
Purr;
end;
To jest dużo czystsze. Żadnych psów wewnętrznych. A koty i psy są na tym samym poziomie. Możemy nawet wprowadzić inne zwierzaki, aby rozszerzyć model. Chyba że jest to ryba lub coś, co nie chodzi. W takim przypadku musimy ponownie dokonać refaktoryzacji. Ale to coś na inny czas.