Zadzwoń super
Call super to zapach kodu lub antywzorzec niektórych obiektowych języków programowania. Call super to wzorzec projektowy, w którym określona klasa określa, że w pochodnej podklasie użytkownik musi przesłonić metodę i wywołać samą przesłoniętą funkcję w określonym punkcie. Zastąpiona metoda może być celowo niekompletna i polegać na metodzie zastępującej w celu rozszerzenia jej funkcjonalności w określony sposób. Jednak fakt, że sam język może nie być w stanie wyegzekwować wszystkich warunków określonych w tym wywołaniu, sprawia, że jest to antywzorzec.
Opis
W programowaniu obiektowym użytkownicy mogą dziedziczyć właściwości i zachowanie nadklasy w podklasach. Podklasa może przesłonić metody swojej nadklasy, zastępując własną implementację metody implementacją nadklasy. Czasami metoda nadrzędna całkowicie zastąpi odpowiadającą jej funkcjonalność w nadklasie, podczas gdy w innych przypadkach metoda nadklasy nadal musi być wywoływana z metody nadrzędnej. Dlatego większość języków programowania wymaga, aby metoda przesłaniająca jawnie wywołała metodę przesłoniętą w nadklasie, aby mogła zostać wykonana.
Wywołanie superantywzorca polega na tym, że użytkownicy interfejsu lub frameworka wyprowadzają podklasę z określonej klasy, przesłaniają określoną metodę i wymagają, aby nadpisana metoda wywołała oryginalną metodę z nadrzędnej metody:
Jest to często wymagane, ponieważ nadklasa musi wykonać pewne zadania konfiguracyjne, aby klasa lub framework działały poprawnie, lub ponieważ główne zadanie nadklasy (które jest wykonywane tą metodą) jest tylko rozszerzane przez podklasę.
Antywzorzec jest wymogiem wywołania rodzica. Istnieje wiele przykładów w prawdziwym kodzie, w których metoda w podklasie może nadal wymagać funkcjonalności nadklasy, zwykle tam, gdzie tylko rozszerza funkcjonalność nadrzędną. Jeśli nadal musi wywoływać klasę nadrzędną, nawet jeśli w pełni zastępuje funkcjonalność, antywzorzec jest obecny.
Lepszym podejściem do rozwiązania tych problemów jest zamiast tego użycie wzorca metody szablonowej , gdzie nadklasa zawiera czysto abstrakcyjną metodę, która musi być zaimplementowana przez podklasy, a oryginalna metoda wywołuje tę metodę:
Odmiana językowa
Pojawienie się tego antywzorca w programach jest zwykle spowodowane tym, że niewiele języków programowania zapewnia funkcję zapewniającą umownie, że super metoda jest wywoływana z klasy pochodnej. Jednym z języków, który ma tę funkcję, w dość radykalny sposób, jest BETA . Funkcja ta występuje w ograniczony sposób na przykład w Javie i C++ , gdzie konstruktor klasy potomnej zawsze wywołuje konstruktora klasy nadrzędnej.
Języki obsługujące metody przed i po , takie jak Common Lisp (w szczególności Common Lisp Object System ), zapewniają inny sposób uniknięcia tego antywzorca. Programista podklasy może, zamiast przesłonić metodę klasy nadrzędnej, dostarczyć dodatkową metodę, która zostanie wykonana przed lub po metodzie klasy nadrzędnej. Ponadto programista nadklasy może określić przed , po i wokół , które gwarantują wykonanie oprócz działań podklasy.
Przykład
Załóżmy, że istnieje klasa do generowania raportu o inwentarzu wypożyczalni wideo. Każdy sklep ma inny sposób zestawienia aktualnie dostępnych filmów, ale algorytm generowania raportu końcowego jest taki sam dla wszystkich sklepów. Framework, który używa superantywzorca wywołania, może udostępniać następującą klasę abstrakcyjną (w C# ):
abstract class ReportGenerator { public virtual Report CreateReport () { // Wygeneruj ogólny obiekt raportu // ... zwróć nowy raport (...); } }
Oczekuje się, że użytkownik klasy zaimplementuje taką podklasę:
class ConcreteReportGenerator : ReportGenerator { public override Report CreateReport () { // Zestawia dane w sposób charakterystyczny dla sklepu // ... // Projekt tej klasy wymaga wywołania funkcji nadrzędnej CreateReport() na // końcu nadpisana funkcja. Należy jednak zauważyć, że ten wiersz można łatwo pominąć lub // zwrócony raport można dalej modyfikować po wywołaniu, naruszając projekt klasy // i być może także format raportu obejmujący całą firmę. baza zwrotna . Utwórz raport (); } }
Preferowany interfejs wygląda następująco:
Klasa abstrakcyjna ReportGenerator { Public Report CreateReport () { Tabulate (); // Wygeneruj obiekt raportu ogólnego // ... zwróć nowy raport (...); } chroniony streszczenie void Tabulate (); }
Implementacja zastąpiłaby tę klasę w następujący sposób:
class ConcreteReportGenerator : ReportGenerator { protected override void Tabulate () { // Zestawianie danych w sposób charakterystyczny dla sklepu // ... } }