Niezależnie od tego, czy obiekt istnieje fizycznie, czy nie, możemy modelować go na różne sposoby. W wielu przypadkach moglibyśmy arbitralnie zastosować uogólnienie lub kompozycję. Jednak zasada GoF „faworyzuj kompozycję zamiast uogólnienia [sic]” prowadzi nas do użycia kompozycji. Kiedy modelujemy na przykład linię, tworzymy klasę zawierającą dwa elementy PointA i PointB typu Point (kompozycja) zamiast rozszerzania Point (uogólnienie). Jest to tylko uproszczony przykład tego, w jaki sposób możemy arbitralnie wybrać kompozycję lub dziedziczenie do modelu, mimo że obiekty są zwykle znacznie bardziej złożone.
Skąd wiemy, że jest to właściwy wybór? Ma to znaczenie przynajmniej dlatego, że może być mnóstwo refaktoryzacji, jeśli jest źle?
object-oriented
inheritance
composition
class-design
CarneyCode
źródło
źródło
Odpowiedzi:
Nie zawsze jest to właściwy wybór. W większości przypadków jest to korzystne . Gdy model złożony wymaga zmiany lub rozszerzenia, jest znacznie bardziej odporny na to, ponieważ można zmienić skład bez obawy, że wpłynie on na inne klasy przypadkowo.
Skąd to wiemy? Z doświadczenia i doświadczenia innych.
Widziałem wiele sytuacji, w których ogromna hierarchia klas wyrosła z tego, co zaczęło się jako prosta koncepcja, i tam właśnie konieczne staje się twoje poważne refaktoryzowanie. Tymczasem nigdy nie widziałem sytuacji, w której struktura kompozycji wymagałaby refaktoryzacji do dziedziczenia.
Ale moje anegdotyczne dowody nie powinny wystarczyć. Wystarczy rozejrzeć się po Internecie, a spora liczba osób miała takie same doświadczenia.
źródło
Jeśli chcesz mieć silniejszą ogólną zasadę wykraczającą poza „faworyzowanie kompozycji zamiast dziedziczenia”, mógłbym zaproponować coś takiego:
Z dwóch sposobów specjalizacji obiektu - Dziedziczenie i Kompozycja - należy używać dziedziczenia tylko wtedy, gdy potrzebujesz, aby Twój obiekt był polimorficzny (zastępowalny) dla klasy podstawowej, którą specjalizujesz.
Jednak jak wszystkie praktyczne zasady, kiedy zrozumiesz regułę - wtedy możesz ją złamać :)
źródło
Nie rozumiem, w jaki sposób kompozycja i uogólnienie są alternatywami i nie udało mi się znaleźć cytatu .
Skład i dziedziczenie są (w celu osiągnięcia specjalizacji) i można argumentować, że abstrakcja i uogólnienie są (w celu osiągnięcia modułowości).
To, czego chcesz, to aby Twój projekt był prosty i wiarygodny, a są to dwie cechy, które z natury dość łatwo można zmierzyć.
W twoim przypadku bardziej prawdopodobne wydaje się skomponowanie linii dwóch punktów zamiast jej przedłużenia, ponieważ naturalnie zdefiniowałbyś linię o dwa punkty, zamiast rozszerzając koncepcję punktu.
źródło
Przysługa zdarza się, gdy obaj kandydaci się kwalifikują. Problem wskazany w pytaniu zawodzi na tym koncie, ponieważ ma on tylko opcję składu.
„Kompozycja mogłaby również użyć uogólnienia”. Czy to stwierdzenie ma dla nas sens? Jeśli nie, to nie jesteśmy jeszcze gotowi na przyjęcie zasady „przychylności”.
Dlatego preferujemy Composition, ponieważ Composition oferuje więcej możliwości rozszerzenia / elastyczności niż generalizacja. To rozszerzenie / elastyczność dotyczy głównie środowiska wykonawczego / elastyczności dynamicznej (co osiąga się dzięki połączeniu interfejsów i kompozycji).
Korzyści nie są natychmiast widoczne. Aby zobaczyć korzyści, musisz poczekać na kolejne nieoczekiwane żądanie zmiany. Tak więc w większości przypadków ci, którzy trzymali się uogólnienia, zawodzą w porównaniu z tymi, którzy przyjęli kompozycję (z wyjątkiem jednego oczywistego przypadku wspomnianego później). Stąd zasada. Z naukowego punktu widzenia, jeśli możesz skutecznie wdrożyć zastrzyk zależności, powinieneś wiedzieć, który z nich preferować i kiedy. Reguła pomaga w podjęciu decyzji, gdy nie jesteś pewien, który wybrać. Ponownie powinieneś być w stanie zobaczyć obie opcje w pierwszej kolejności, aby faworyzować jedną z nich.
Podsumowanie: Kompozycja: Sprzęganie jest redukowane przez tylko kilka mniejszych rzeczy, które podłączasz do czegoś większego, a większy obiekt po prostu wywołuje z powrotem mniejszy obiekt. Generalizacja: Z punktu widzenia interfejsu API innej firmy zdefiniowanie, że metoda może zostać zastąpiona, jest silniejszym zobowiązaniem niż zdefiniowanie, że można wywołać metodę (pewnie wygrana w przypadku Generalizacji). I nigdy nie zapominaj, że w kompozycji używasz również uogólnienia, z interfejsu zamiast dużej klasy. Niestety cały kredyt należy do składu.
źródło
Dzisiaj napisałem o 300 LoC. I nie pamiętam żadnej zasady, którą mógłbym naruszać i której nie naruszałem. Mam nadzieję, że refaktoryzacja uratuje moją duszę.
Jeśli abstrakcja jest podyktowana przez interfejs strony 3D - zwykle poprawne jest użycie dziedziczenia. W krajowym projekcie podmiot musi być abstrakcyjny lub zapieczętowany. Podmiot abstrakcyjny potencjalnie musi mieć około 3 spadkobierców. Nie lubię punktów rozszerzeń z jedną metodą wirtualną. Wszystko powyżej dotyczy mojego smaku. Nie mówię o abstrakcji interfejsu, która jest kompletną inną historią.
źródło