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.
Wyzwanie
ŁatwyZbudujmy 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 szablonowagenerateReport()powinna wykonywać kolejno następujące kroki:gatherData(): czysto wirtualna, musi być zaimplementowana przez klasy pochodneformatReport(): czysto wirtualna, musi być zaimplementowana przez klasy pochodneaddHeader(): metoda hakowa z domyślnym działaniem, która wypisuje--- Report ---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()wypisujeGathering sales data from databaseformatReport()wypisujeFormatting sales figuresprintReport()wypisujeSales Total: $[amount], gdzie amount jest przekazywane do konstruktora
Utwórz klasę
InventoryReport, która:gatherData()wypisujeScanning inventory recordsformatReport()wypisujeOrganizing inventory by categoryaddHeader()nadpisuje metodę hakową, aby wypisać=== Inventory Report ===printReport()wypisujeItems 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:
- Kwota sprzedaży (liczba całkowita)
- Liczba pozycji w magazynie (liczba całkowita)
Utwórz obiekt
SalesReportz kwotą sprzedaży i wygeneruj raport. Następnie utwórz obiektInventoryReportz 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: 250Dla 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: 120Zwróć 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;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów11Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieMixiny z użyciem CRTPIdiom PimplWymazywanie typówKlasy enum i silne typowanieObsługa wyjątków w OOPWłasne hierarchie wyjątków14Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytuRAII jako wzorzec3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generycznyPoćwicz samodzielnie: Kompilator C++ online