Niedawno musiałem zaktualizować abstrakcyjną klasę bazową w niektórych OSS, których używałem, aby była bardziej testowalna, czyniąc je wirtualnymi (nie mogłem użyć interfejsu, ponieważ łączył dwa). To sprawiło, że pomyślałem, czy powinienem zaznaczyć wszystkie metody, których potrzebowałem wirtualny, czy też powinienem oznaczyć każdą publiczną metodę / właściwość wirtualną. I na ogół zgadzają się z Roy Osherove że każda metoda powinna być wirtualny, ale natknąłem się na ten artykuł, który mi do myślenia o tym, czy było to konieczne, czy nie . Dla uproszczenia ograniczę to jednak do klas abstrakcyjnych (jestem pewien, że wszystkie konkretne metody publiczne powinny być wirtualne).
Widziałem, gdzie możesz pozwolić, aby podklasa korzystała z metody, ale nie chcę, aby zastąpiła ona implementację. Jeśli jednak wierzysz, że zasada Liskowa będzie przestrzegana, to dlaczego nie pozwolisz, aby została ona nadpisana? Oznaczając go jako abstrakcyjny, i tak wymuszasz pewne przesłonięcie, więc wydaje mi się, że wszystkie metody publiczne w klasie abstrakcyjnej powinny być rzeczywiście oznaczone jako wirtualne.
Chciałem jednak zapytać na wypadek, gdyby było coś, o czym mógłbym nie myśleć. Czy wszystkie metody publiczne w klasie abstrakcyjnej powinny być wirtualne?
źródło
Odpowiedzi:
Na przykład, ponieważ chcę, aby szkieletowa implementacja algorytmu została naprawiona i zezwalam (tylko) na określone części do (pod) definicji podklas. Jest to powszechnie znane jako wzorzec metody szablonów (moje podkreślenie poniżej):
Aktualizacja
Kilka konkretnych przykładów projektów, nad którymi pracowałem:
W pierwszych dwóch przypadkach pierwotna implementacja starszego typu korzystała ze strategii , co skutkowało mnóstwem zduplikowanego kodu, który oczywiście z biegiem lat narastał subtelne różnice tu i tam, zawierał wiele zduplikowanych lub nieco różnych błędów i był bardzo trudny do utrzymania. Refaktoryzacja do metody szablonu (i niektórych innych ulepszeń, takich jak stosowanie adnotacji Java) zmniejszyła rozmiar kodu o około 40-70%.
To tylko najnowsze przykłady, które przychodzą mi na myśl. Mógłbym przytoczyć więcej przypadków z prawie każdego projektu, nad którym do tej pory pracowałem.
źródło
Całkowicie uzasadnione, a czasem pożądane jest posiadanie nie-wirtualnych metod w abstrakcyjnej klasie bazowej; tylko dlatego, że jest to klasa abstrakcyjna, niekoniecznie oznacza, że każda jej część powinna być użyteczna polimorficznie.
Na przykład możesz użyć idiomu „Wirtualny polimorfizm”, w którym funkcja jest wywoływana polimorficznie z nie-wirtualnej funkcji składowej, aby zapewnić spełnienie określonych warunków wstępnych lub dodatkowych przed wywołaniem funkcji wirtualnej
źródło
Wystarczy, aby klasa zawierała JEDNĄ metodę wirtualną, aby klasa stała się abstrakcyjna. Możesz zwrócić uwagę na to, które metody chcesz wirtualne, a które nie, w zależności od rodzaju polimorfizmu, którego planujesz użyć.
źródło
Zadaj sobie pytanie, jakie zastosowanie ma metoda nie-wirtualna w klasie abstrakcyjnej. Taka metoda musiałaby mieć implementację, aby była użyteczna. Ale jeśli klasa ma implementację, czy nadal można ją nazwać klasą abstrakcyjną? Nawet jeśli pozwala na to język / kompilator, czy ma to sens? Osobiście nie sądzę. Miałbyś normalną klasę z abstrakcyjnymi metodami, które potomkowie powinni wdrożyć.
Moim podstawowym językiem jest Delphi, a nie C #. W Delphi, jeśli zaznaczysz streszczenie metody, musisz także oznaczyć ją jako wirtualną, inaczej kompilator narzeka. Nie śledziłem zbyt uważnie najnowszych zmian językowych, ale jeśli klasy abstrakcyjne są w Delphi lub przybędą do nich, oczekiwałbym, że kompilator będzie narzekał na wszelkie metody nie-wirtualne, metody prywatne i implementacje metod dla klasy oznaczonej jako abstrakcyjne na poziomie klasy.
źródło
abstract
, musisz także zaznaczyć całą klasęabstract
.Nie czynisz niektórych metod wirtualnymi, ponieważ nie uważasz, że tak jest. Ponadto, czyniąc niektóre metody nie wirtualnymi, sygnalizujesz dziedzicom, które metody należy wdrożyć.
Osobiście często sprawiam, że przeciążenia metod, które istnieją dla wygody, nie są wirtualne, aby użytkownicy klasy mogli mieć spójne ustawienia domyślne, a realizatorzy nie byli nawet w stanie popełnić błędu zerwania tego dorozumianego zachowania.
źródło