Template Method
Motivační příklad – reálný svět Čaj 1) Uvař vodu 2) Dej do hrnku sáček čaje 3) Zalij hrnek 4) Přisyp cukr a vymačkej citrón Káva 1) Uvař vodu 2) Nasyp kávu do hrnku 3) Zalij hrnek 4) Přidej cukr a vlij mléko Čaj/káva 1) Uvař vodu 2) Dej základ do hrnku 3) Zalij hrnek 4) Přidej doplňky Čaj Základ:vložit čaj Doplňky:cukr, citrón Káva Základ:nasypat kávu Dopňky:cukr, mléko
Template method – Obecně Název Trochu zavádějící, používaný Definice Definuje kostru algoritmu a nechává některé kroky implementovat podtřídami Účel Umožnit podtřídám měnit části algoritmu beze změny struktury algoritmu Pevné kroky algoritmu jen jednou, měnící se části do podtříd Kdy použít Implementují-li podtřídy společný nebo podobný algoritmus Je-li třeba kontrolovat, ve kterých místech smějí podtřídy měnit chování předka Kde použito V každém frameworku (jdk,.net sdk, JUnit...)
Motivace Framework pro aplikace nad dokumenty Postup načtení dokumentu ze souboru Ověřit, zda soubor existuje a aplikace umí s daným typem pracovat Vytvořit instanci příslušné konkrétní třídy dokumentu Přidat ji do kolekce otevřených dokumentů Zobrazit uživateli zprávu o načítání dokumentu Otevřít soubor Načíst dokument Osnova zůstává, konkrétní kroky záleží na typu dokumentu Možná řešení Abstraktní metoda OpenDocument v každém potomkovi se znovu píše celá implementace nejvýš se mohou volat nějaké pomocné metody předka nemusí se dodržovat stejná osnova Template method
Obecná struktura AbstractClass definuje abstraktní primitivní operace implementuje kostru algoritmu ConcreteClass implementuje primitivní operace - konkrétní části algoritmu Inverzní princip (Hollywood principle) „Don’t call us, we’ll call you“ Rodičovská třída volá metody potomků (ne opačně) implementace kostry pomocí virtuálních metod
bool Application::OpenDocument() { if (!CanOpenDocument(name)) return false; Document *doc = DoCreateDocument(); if (doc) { _docs->AddDocument(doc); AboutToOpenDocument(doc); doc->Open(name); doc->DoRead(); } return true; } Konkrétní struktura OpenDocument() – Template method, definuje kostru DoCreateDocument(), CanOpenDocument() – primitivní operace Odvozené třídy definují konkrétní chování
Důsledky, implementace Operace v template method Konkrétní operace abstraktní třídy – užitečné pro všechny podtřídy Primitivní operace – abstraktní, musí být implementovány v potomkovi Hook operace – defaultní implementace, může být přepsána v potomkovi jasně definované body rozšíření Přístupová práva a modifikátory template method – public, nevirtuální primitivní operace – protected, čistě virtuální hook operace - protected, virtuální s implementací Minimalizace počtu primitivních operací všechny je nutné definovat větší množství komplikuje implementaci
Příklad implementace class Base { protected: void preHook() {} void postHook() {} virtual void doPh1() = 0; virtual void doPh2() = 0; public: void execute() { preHook(); doPh1(); doPh2(); postHook(); } }; class One: public Base { void doPh1() { cout << "b"; } void doPh2() { cout << "d"; } void postHook() { /*...*/ } }; class Two: public Base { void doPh1() { cout << "2"; } void doPh2() { cout << "4"; } void preHook() { /*...*/ } }; primitivní operace čistě virtuální hooks volitelně přepsatelné
Policy classes Použití šablon kompilační polymorfismus výběr metod v době kompilace vyšší výkonnost různé jazyky mají různou úroveň specifikace rozhraní class PolX { public: static void op1() {} static void op2() {} }; template class Base { public: void execute() { pol::op1(); pol::op2();} }; int main() { Base tm; tm.execute(); }
Příklad – JUnit testy Při každém automatickém testu spustit několik akcí runBare() – Template method setUp() – připraví zdroje runTest() – vykoná test tearDown() – uvolní zdroje public abstract class TestCase { public void runBare() { setUp(); try { runTest(); } finally { tearDown(); } protected void setUp() {} protected void tearDown() {} protected void runTest() {} }
Rozdrobenost kousky kódu jsou vytržené z kontextu Složitější přidávání nových funkcí dědění umožňuje rozšíření pouze jedné dimenze problému Modernější alternativa šablony - policy classes Nevýhody Template method
Template method - Shrnutí Problém definice obecného algoritmu, zachovaná struktura Řešení mateřská třída implementuje kostru algoritmu podtřída implementuje jeho jednotlivé kroky Příklady obecně každý framework/knihovna Související NV Strategy změna celého algoritmu delegací Factory method primitivní operace, např. DoCreateDocument()