Skip to content

Metoda szablonowa (Template method)

Metoda szablonowa definiuje szkielet algorytmu pozostawiając podklasom możliwość wprowadzania zmian do niektórych jego części. Oznacza to, że gdy wykonujemy bardzo zbliżone zadania wielokrotnie, to dzięki metodzie szablonowej możemy modyfikować poszczególne kroki algorytmu pod nasz konkretny przypadek, a resztę pozostawiać niezmienioną. Jest to jedna z podstawowych technik powtórnego wykorzystania kodu, która umożliwia eleganckie wyodrębnienie wspólnego zachowania w hierarchii klas. Co istotne, przy stosowaniu metody szablonowej, to klasa nadrzędna wywołuje operacje podklasy (tzw. „zasada Hollywoodu”).

Schemat metody szablonowej można przedstawić następująco:

public abstract class TemplateMethod {

  // Alghoritm step by step
  public void perform() {
    stepOne();
    stepTwo();
    stepThree();
    stepFour();
    stepFive();
  }

  protected abstract void stepOne();

  protected void stepTwo() {
    // Do something...
  }

  private void stepThree() {
    // Do something...
  }

  protected abstract void stepFour();

  protected void stepFive() {
    // Do something...
  }
}

Metoda perform() zawiera w sobie szkielet naszego algorytmu. Oznacza to, że musi on być wykonany właśnie w tej kolejności. Następnie definiujemy trzy rodzaje metod:

  1. protected abstract – operacje abstrakcyjne. W ten sposób określamy elementy algorytmu, które muszą zostać zmienione dla każdego przypadku
  2. protected – są to tzw. „punkty zaczepienia”. Udostępniają one domyślną implementację, która w razie potrzeby może zostać zmieniona na rzecz podklasy
  3. private – w ten sposób zaznaczamy elementy algorytmu, które mają pozostać niezmienione dla każdego przypadku (jeżeli takie istnieją)

Kiedy korzystać z metody szablonowej?

  • W celu jednorazowego zaimplementowania niezmiennych części algorytmu oraz umożliwienia dokonania zmian działania w pewnych zachowania specyficznych dla podklas
  • W celu wyodrębnienia wspólnego zachowania i umieszczenia go w jednej klasie celem eliminacji powielania kodu
  • W celu kontroli rozszerzania podklas. Definiujemy metodę szablonową wywołującą w odpowiednich miejscach „punkty zaczepienia”, co umożliwia rozszerzanie podklas tylko w tych punktach

Kwestie implementacyjne

  1. Kontrola dostępu – operacje proste wykonywane przez metodę szablonową, można zadeklarować jako składowe chronione. Dzięki temu mamy pewność, że będą one wywołane tylko i wyłącznie przez nią. Operacje proste, które trzeba przesłonić deklarujemy jako abstrakcyjne. Samej metody szablonowej nie należy przesłaniać, dlatego nie może ona być abstrakcyjna
  2. Minimalizacja liczby operacji prostych – istotną kwestią w momencie projektowania metody szablonowej jest minimalizacja liczby operacji prostych, które będzie trzeba później przesłaniać w podklasach.
  3. Konwencje nazwenicze – dobrą praktyką jest wyróżnienie metod przeznaczonych do przesłonięcia poprzez dodanie odpowiedniego przedrostka do ich nazwy (np. poprzez dodanie „do” – doSomething())

Przykład

Uznałem, że nie ma sensu powielać dziesiątek innych, dobrych i prostych przykładów, które ktoś już opracował w celach dydaktycznych.

Przykład pochodzi ze strony (nie jestem jego autorem):

 https://sourcemaking.com/design_patterns/template_method/java/2

abstract class Generalization {
    // 1. Standardize the skeleton of an algorithm in a "template" method
    public void findSolution() {
        stepOne();
        stepTwo();
        stepThr();
        stepFor();
    }

    // 2. Common implementations of individual steps are defined in base class
    protected void stepOne() {
        System.out.println("Generalization.stepOne");
    }

    // 3. Steps requiring peculiar impls are ";placeholders" in the base class
    abstract protected void stepTwo();

    abstract protected void stepThr();

    protected void stepFor() {
        System.out.println("Generalization.stepFor");
    }
}

abstract class Specialization extends Generalization {
    // 4. Derived classes can override placeholder methods
    // 1. Standardize the skeleton of an algorithm in a "template" method
    protected void stepThr() {
        step3_1();
        step3_2();
        step3_3();
    }

    // 2. Common implementations of individual steps are defined in base class
    protected void step3_1() {
        System.out.println("Specialization.step3_1");
    }

    // 3. Steps requiring peculiar impls are "placeholders" in the base class
    abstract protected void step3_2();

    protected void step3_3() {
        System.out.println("Specialization.step3_3");
    }
}

class Realization extends Specialization {
    // 4. Derived classes can override placeholder methods
    protected void stepTwo() {
        System.out.println("Realization   .stepTwo");
    }

    protected void step3_2() {
        System.out.println("Realization   .step3_2");
    }

    // 5. Derived classes can override implemented methods
    // 6. Derived classes can override and "call back to" base class methods
    protected void stepFor() {
        System.out.println("Realization   .stepFor");
        super.stepFor();
    }
}

class TemplateMethodDemo {
    public static void main(String[] args) {
        Generalization algorithm = new Realization();
        algorithm.findSolution();
    }
}

Źródła:

Facebooktwitterredditlinkedinmail
Published inProgramowanieWzorce projektowe