Mam klasę, która otacza inną klasę wspólnego typu podstawowego. Ponieważ interfejs typu podstawowego jest dość duży, wymaga to napisania wielu funkcji tranzytowych. Szukam sposobu, aby tego uniknąć.
Zróbmy przykład:
Car
/ \
Volvo VolvoWithTrailer
Teraz muszę zaimplementować każdą funkcję w interfejsie samochodowym VolvoWithTrailer i wywołać odpowiednią funkcję na zawiniętym obiekcie Volvo, z wyjątkiem może GetMaxSpeed (), która zwróci coś niższego. Zasadniczo będę miał wiele funkcji takich jak
int VolvoWithTrailer::GetNumSeats() {
return mVolvo.GetNumSeats()
}
Oczywistym sposobem rozwiązania tego problemu byłoby uczynienie VolvoWithTrailer podklasą Volvo
Car
|
Volvo
|
VolvoWithTrailer
ale wydaje się to naruszać zasadę faworyzowania kompozycji nad dziedziczeniem.
Jak inaczej mogę uniknąć pisania tych wszystkich opakowań (językiem jest C ++)? Lub - jeśli takie jest Twoje stanowisko - dlaczego powinienem je po prostu napisać / po prostu użyć dziedziczenia? Czy jest jakaś magia szablonu, która mogłaby w tym pomóc?
źródło
Odpowiedzi:
Uważam, że powinieneś pisać wszystko, co potrzebujesz, aby poprawić długoterminową stabilność i łatwość konserwacji programu. Jaki jest sens unikania pisania 20 wierszy kodu dzisiaj, jeśli za każdym razem, gdy dotkniesz czegoś, co używa tego kodu lub wrócisz, aby utrzymać tę klasę, kosztuje to dodatkowe 5 minut lub więcej, ponieważ dzisiaj nie poświęciłeś czasu?
Zatem pytanie brzmi: „co musisz napisać?” Nie sądzę, abyś dostarczył wystarczającą ilość informacji, aby udzielić ostatecznej odpowiedzi, dlatego wymienię tylko kilka rzeczy, o których pomyślałem przy podejmowaniu decyzji:
1. Czy potrzebujesz obiektu Trailer samodzielnie, teraz czy w dającej się przewidzieć przyszłości?
Jeśli tak, masz całkiem niezły argument za tym, aby otoczyć oba złożone obiekty, ponieważ już będziesz musiał owinąć jeden lub drugi. Równie dobrze może być konsekwentny.
2. Czy którykolwiek z trzech typów (Car, Trailer, CarWithTrailer) w obszarze kodu, w który programiści często się pojawiają lub wyglądają na podobnego?
Jeśli tak, bądź bardzo ostrożny, ponieważ konsekwencje wyboru niewłaściwej rzeczy mogą być bardzo kosztownie amortyzowane przy każdym dotknięciu kodu. Jeśli nie, może nie mieć znaczenia, co wybierzesz. Po prostu wybierz kierunek i idź nim.
3. Co najłatwiej zrozumieć?
Czy jedno podejście rzuca się na ciebie, że ktoś idący za tobą natychmiast „dostanie” to, co próbujesz zrobić? Czy twoi koledzy z drużyny mają jakieś uprzedzenia, które mogą utrudniać utrzymanie jednego podejścia? Jeśli wszystkie rzeczy są równe, wybierz rozwiązanie, które nakłada najniższe obciążenie poznawcze.
4. Czy są jakieś dodatkowe zalety korzystania z jednego podejścia nad drugim?
Jedną rzeczą, która mnie zaskakuje, jest to, że pomysł owijania ma wyraźną zaletę, jeśli napiszesz, że CarWithTrailerWrapper może owinąć każdy samochód i dowolną przyczepę w CarWithTrailer. Następnie kończysz pisanie wszystkich metod przekazywania, ale piszesz je tylko raz , a nie raz dla każdej klasy samochodu.
To sprawia, że początkowa inwestycja w pisanie metod przekazywania jest znacznie tańsza, gdy dodajesz więcej samochodów i przyczep. Pomaga także zmniejszyć pokusę parowania rzeczy zbyt bezpośrednio z Volvo lub VolvoWithTrailer, jednocześnie zmniejszając konsekwencje sprzężenia z CarWithTrailerWrapper, ponieważ dzięki tej jednej implementacji możesz zrobić znacznie więcej.
Może istnieją wyraźne zalety, które można uzyskać za darmo przy użyciu metody rozszerzenia, ale ich nie widzę.
OK, więc wygląda na to, że rozmawiałem o tym, by iść naprzód i wypełniać metody tranzytowe, dla nietrywialnych aplikacji.
Nie jestem programistą C ++, więc nie mam pojęcia, jakie narzędzia do generowania kodu są dostępne. IDE, którego używam, może generować metody z interfejsu, i mogę dodawać szablony kodu , dzięki którym pisanie przejść byłoby dość bezbolesne. Jeśli nie masz dostępu do IDE, które to robi, możesz dostać się daleko, pozwalając programowi Excel napisać kod za ciebie .
źródło
I jest twój problem.
Interfejsy powinny obsługiwać tylko jedną odpowiedzialność. Utrzymywanie ich cienkimi i skoncentrowanymi ogranicza ilość prac związanych z przekazywaniem danych, które mogą być konieczne w przypadku dekoratora, serwera proxy lub innego opakowania (oprócz uczynienia prostego klasy do używania, testowania, utrzymywania i rozszerzania).
źródło