Menu
Coddy logo textTech

Wzorzec metody szablonowej

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 99 z 104.

Wzorzec metody szablonowej definiuje szkielet algorytmu w klasie bazowej, umożliwiając podklasom nadpisywanie określonych kroków bez zmiany ogólnej struktury algorytmu. W przeciwieństwie do wzorca Strategia, który wymienia całe algorytmy, metoda szablonowa utrzymuje algorytm bez zmian, pozwalając jednocześnie na dostosowywanie poszczególnych kroków.

Klasa bazowa implementuje metodę szablonową (algorytm) i wywołuje metody abstrakcyjne lub wirtualne, które muszą dostarczyć podklasy:

#include <iostream>

class DataProcessor {
public:
    // Metoda szablonowa - definiuje szkielet algorytmu
    void process() {
        loadData();
        processData();
        saveResults();
    }
    
    virtual ~DataProcessor() = default;
    
protected:
    virtual void loadData() = 0;      // Musi zostać zaimplementowana
    virtual void processData() = 0;   // Musi zostać zaimplementowana
    
    // Metoda hakowa - można ją opcjonalnie nadpisać; ma domyślne działanie
    virtual void saveResults() {
        std::cout << "Saving to default location\n";
    }
};

class CSVProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading CSV file\n";
    }
    void processData() override {
        std::cout << "Parsing CSV data\n";
    }
};

class JSONProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading JSON file\n";
    }
    void processData() override {
        std::cout << "Parsing JSON data\n";
    }
    void saveResults() override {
        std::cout << "Saving to cloud storage\n";
    }
};

int main() {
    CSVProcessor csv;
    csv.process();  // Używa domyślnej implementacji saveResults
    
    JSONProcessor json;
    json.process(); // Używa własnej implementacji saveResults
}

Metoda process() jest metodą szablonową — definiuje stałą kolejność kroków. Podklasy implementują loadData() i processData() na różne sposoby, ale kolejność nigdy się nie zmienia. Metoda saveResults() jest „hakiem” — ma domyślną implementację, którą podklasy mogą opcjonalnie nadpisać.

Użyj wzorca Template Method, gdy masz algorytm z niezmiennymi krokami, ale potrzebujesz elastyczności w przypadku określonych operacji lub chcesz uniknąć duplikowania kodu w podobnych klasach.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system Generator raportów z wykorzystaniem wzorca Template Method. Stworzysz strukturę, w której różne typy raportów (takie jak raporty sprzedaży i raporty magazynowe) są generowane według tego samego procesu, ale każdy typ raportu dostosowuje określone kroki. To idealny przykład zastosowania wzorca Template Method: ogólny przebieg pracy pozostaje niezmienny, a poszczególne kroki mogą się różnić.

Rozmieścisz kod w trzech plikach:

  • ReportGenerator.h: Zdefiniuj abstrakcyjną klasę bazową z metodą szablonową.

    Utwórz klasę ReportGenerator, która definiuje szkielet algorytmu generowania raportu. Twoja metoda szablonowa generateReport() powinna wykonywać kolejno następujące kroki:

    1. gatherData(): czysto wirtualna, musi być zaimplementowana przez klasy pochodne
    2. formatReport(): czysto wirtualna, musi być zaimplementowana przez klasy pochodne
    3. addHeader(): metoda hakowa z domyślnym działaniem, która wypisuje --- Report ---
    4. printReport(): czysto wirtualna, musi być zaimplementowana przez klasy pochodne

    Metoda addHeader() pełni funkcję metody hakowej, którą klasy pochodne mogą opcjonalnie nadpisać, aby dostosować nagłówek.

  • Reports.h: Zaimplementuj dwa konkretne generatory raportów.

    Utwórz klasę SalesReport, która:

    • gatherData() wypisuje Gathering sales data from database
    • formatReport() wypisuje Formatting sales figures
    • printReport() wypisuje Sales Total: $[amount], gdzie amount jest przekazywane do konstruktora

    Utwórz klasę InventoryReport, która:

    • gatherData() wypisuje Scanning inventory records
    • formatReport() wypisuje Organizing inventory by category
    • addHeader() nadpisuje metodę hakową, aby wypisać === Inventory Report ===
    • printReport() wypisuje Items in stock: [count], gdzie count jest przekazywane do konstruktora

    Obie klasy powinny przyjmować odpowiednie wartości (amount lub count) za pośrednictwem konstruktorów.

  • main.cpp: Zademonstruj wzorzec Template Method.

    Wczytaj dwie wartości:

    1. Kwota sprzedaży (liczba całkowita)
    2. Liczba pozycji w magazynie (liczba całkowita)

    Utwórz obiekt SalesReport z kwotą sprzedaży i wygeneruj raport. Następnie utwórz obiekt InventoryReport z liczbą pozycji w magazynie i wygeneruj raport. Dla czytelności wypisz pustą linię między raportami.

Na przykład dla wejść 15000 i 250:

Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $15000

Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 250

Dla wejść 8500 i 120:

Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $8500

Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 120

Zwróć uwagę, że oba raporty wykonują dokładnie tę samą sekwencję kroków zdefiniowaną w generateReport(), ale każdy z nich implementuje te kroki inaczej. Klasa InventoryReport pokazuje również, jak nadpisać metodę hakową, aby dostosować nagłówek, podczas gdy klasa SalesReport korzysta z domyślnego działania. Tak działa wzorzec Template Method: struktura algorytmu jest ustalona w klasie bazowej, ale szczegóły pozostają elastyczne.

Spróbuj swoich sił

#include <iostream>
#include "Reports.h"

using namespace std;

int main() {
    // Wczytaj dane wejściowe
    int salesAmount;
    int inventoryCount;
    cin >> salesAmount;
    cin >> inventoryCount;
    
    // TODO: Utwórz obiekt SalesReport z salesAmount i wygeneruj raport
    
    // TODO: Wypisz pustą linię między raportami
    
    // TODO: Utwórz obiekt InventoryReport z inventoryCount i wygeneruj raport
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online