Wzorzec metody szablonowej - Template method pattern

W programowaniu obiektowym The metoda szablon jest jednym z behawioralnych wzorców projektowych zidentyfikowanych przez Gamma et al. w książce Wzorce projektowe . Metoda szablonowa jest metodą należącą do nadklasy, zwykle abstrakcyjnej nadklasy, i definiuje szkielet operacji w postaci szeregu wysokopoziomowych kroków. Te kroki są same w sobie implementowane przez dodatkowe metody pomocnika w tej samej klasie co metoda szablonu .

Te metody pomocnicze mogą być abstrakcyjne metody , w tym przypadku podklasy są zobowiązane do przedstawienia konkretnych wdrożeń lub metody przechwytujące , które mają pustych korpusów w nadrzędnej. Podklasy mogą (ale nie muszą) dostosowywać operację, zastępując metody przechwytujące. Celem metody szablonowej jest zdefiniowanie ogólnej struktury operacji, przy jednoczesnym umożliwieniu podklasom dopracowania lub ponownego zdefiniowania niektórych kroków.

Przegląd

Ten wzór składa się z dwóch głównych części:

  • „Metoda szablonu” jest zaimplementowana jako metoda w klasie bazowej (zwykle jest to klasa abstrakcyjna ). Ta metoda zawiera kod części całego algorytmu, które są niezmienne. Szablon zapewnia, że ​​nadrzędny algorytm jest zawsze przestrzegany. W metodzie szablonowej części algorytmu, które mogą się różnić, są implementowane przez wysyłanie wiadomości własnych, które żądają wykonania dodatkowych metod pomocniczych . W klasie bazowej te metody pomocnicze mają domyślną implementację lub nie mają jej wcale (to znaczy mogą być metodami abstrakcyjnymi).
  • Podklasy klasy bazowej „wypełniają” puste lub „wariantowe” części „szablonu” określonymi algorytmami, które różnią się w zależności od podklasy. Ważne jest, aby podklasy nie zastępowały samej metody szablonu .

W czasie wykonywania algorytm reprezentowany przez metodę szablonu jest wykonywany przez wysłanie komunikatu szablonu do instancji jednej z konkretnych podklas. Poprzez dziedziczenie rozpoczyna się wykonywanie metody szablonu w klasie bazowej. Gdy metoda szablonu wysyła wiadomość do jednej z metod pomocniczych, żądającej własnej, wiadomość zostanie odebrana przez konkretną instancję podrzędną. Jeśli metoda pomocnika została zastąpiona, zostanie wykonana nadpisująca implementacja w instancji podrzędnej; jeśli nie został zastąpiony, zostanie wykonana odziedziczona implementacja w klasie bazowej. Mechanizm ten zapewnia, że ​​cały algorytm wykonuje te same kroki za każdym razem, a szczegóły niektórych kroków zależą od tego, która instancja otrzymała pierwotne żądanie wykonania algorytmu.

Ten wzorzec jest przykładem odwrócenia kontroli, ponieważ kod wysokiego poziomu nie określa już, jakie algorytmy mają być uruchomione; zamiast tego w czasie wykonywania wybierany jest algorytm niższego poziomu.

Niektóre wiadomości wysyłane metodą szablonu mogą dotyczyć metod przechwytywania . Metody te są zaimplementowane w tej samej klasie bazowej, co metoda szablonu, ale z pustymi treściami (tj. Nic nie robią). Istnieją metody przechwytujące, dzięki czemu podklasy mogą je przesłonić, a tym samym mogą precyzyjnie dostroić działanie algorytmu bez konieczności zastępowania samej metody szablonu. Innymi słowy, zapewniają one „haczyk”, na którym można „zawiesić” warianty implementacji.

Struktura

Diagram klas UML

Przykładowy diagram klas UML dla wzorca projektowego Template Method.

W powyższym UML schemacie klasy , że AbstractClass definiuje templateMethod() operację definiujący szkielet (matrycy), o zachowanie przez

  • implementowanie niezmiennych części zachowania i
  • wysyłanie do siebie komunikatów primitive1() i primitive2() , które, ponieważ są zaimplementowane SubClass1 , pozwalają tej podklasie zapewnić wariantową implementację tych części algorytmu.
Metoda szablonu w LePUS3 .

Stosowanie

Metoda szablonu jest używana w strukturach, w których każda implementuje niezmienne części architektury domeny, zapewniając jednocześnie metody przechwytujące do dostosowywania. To jest przykład odwrócenia kontroli . Metoda szablonowa jest używana z następujących powodów.

  • Pozwala podklasom na implementowanie różnych zachowań (poprzez nadpisywanie metod przechwytujących).
  • Pozwala to uniknąć powielania kodu: ogólny przepływ pracy algorytmu jest zaimplementowany raz w metodzie szablonu klasy abstrakcyjnej, a niezbędne wariacje są zaimplementowane w podklasach.
  • Kontroluje punkt (y), w których specjalizacja jest dozwolona. Gdyby podklasy miały po prostu zastąpić metodę szablonową, mogłyby wprowadzić radykalne i dowolne zmiany w przepływie pracy. W przeciwieństwie do tego, zastępując tylko metody zaczepienia, można zmienić tylko niektóre określone szczegóły przepływu pracy, a ogólny przepływ pracy pozostaje nienaruszony.

Używaj z generatorami kodu

Wzorzec szablonu jest przydatny podczas pracy z kodem generowanym automatycznie. Wyzwanie związane z pracą z wygenerowanym kodem polega na tym, że zmiany w kodzie źródłowym prowadzą do zmian w wygenerowanym kodzie; jeśli w wygenerowanym kodzie dokonano odręcznych modyfikacji, zostaną one utracone. Jak zatem należy dostosować wygenerowany kod?

Wzorzec szablonu zapewnia rozwiązanie. Jeśli wygenerowany kod jest zgodny ze wzorcem metody szablonu, cały wygenerowany kod będzie abstrakcyjną nadklasą. Pod warunkiem, że dostosowania odręczne są ograniczone do podklasy, generator kodu można uruchomić ponownie bez ryzyka nadpisania tych modyfikacji. W przypadku użycia z generowaniem kodu ten wzorzec jest czasami nazywany wzorcem przerwy między generacjami .

Przykład PHP

abstract class Game
{
    abstract protected function initialize();
    abstract protected function startPlay();
    abstract protected function endPlay();

    /** Template method */
    public final function play()
    {
        /** Primitive */
        $this->initialize();

        /** Primitive */
        $this->startPlay();

        /** Primitive */
        $this->endPlay();
    }
}

class Mario extends Game
{
    protected function initialize()
    {
        echo "Mario Game Initialized! Start playing.", PHP_EOL;
    }

    protected function startPlay()
    {
        echo "Mario Game Started. Enjoy the game!", PHP_EOL;
    }

    protected function endPlay()
    {
        echo "Mario Game Finished!", PHP_EOL;
    }

}

class Tankfight extends Game
{
    protected function initialize()
    {
        echo "Tankfight Game Initialized! Start playing.", PHP_EOL;
    }

    protected function startPlay()
    {
        echo "Tankfight Game Started. Enjoy the game!", PHP_EOL;
    }

    protected function endPlay()
    {
        echo "Tankfight Game Finished!", PHP_EOL;
    }

}

$game = new Tankfight();
$game->play();

$game = new Mario();
$game->play();

Zobacz też

Bibliografia

Linki zewnętrzne