/ janturon.cz / Od kodéra k analytikovi / Tovární metoda a Šablonová metoda

Tovární metoda a Šablonová metoda

Tovární metoda (Factory Method)

Někdy je k vytváření objektů nutno volat větší množství nastavovacích metod či dokonce dodržet jejich pořadí. To je antivzor: žádný koncový uživatel si nebude pamatovat co a v jakém pořadí se má volat, místo toho zkopíruje funkční kód a udělá drobné změny. To je počátek zahnívajícího kódu:

class Coffee { bool milk, whip, ice; int weight; public: Coffee() { milk = whip = ice = false; weight = 7; } void setWeight(w) { weight = w; } void addMilk() { milk = true; } void addWhip() { whip = true; } void addIce() { ice = true; } virtual void mix() { } } int main() { /* tohle si nikdo nezapamatuje koncový uživatel to bude kopírovat */ Coffee* frappe = new Coffee(); frappe->addMilk(); frappe->addIce(); frappe->mix(); }

Výšeuvedenému nešvaru se vyhneme přenesením činnosti vytváření kódu přímo do třídy: Tovární metoda supluje konstruktor, vrací objekt typu třídy, ve které je napsána:

class Coffee() { ... static Coffee* Frappe() { Coffee* frappe = new Coffee(); frappe->addMilk(); frappe->addIce(); frappe->mix(); return frappe; } } int main() { Coffee* frappe = Coffee::Frappe(); }

Šablonová metoda (Template Method)

Umožňuje podobně jako Strategy k separaci algoritmu do samostatné třídy, místo agregace tak ale činí pomocí dědičnosti. Template method použijeme tam, kde mají všechny algoritmy společnou strukturu: dědičnost umožní implementovat pouze část, která se liší od ostatních.

Příkladem může být kompozice e-mailu: pokud se formlní a neformální e-mail liší různým oslovením a podpisem, lze je implementovat pomocí dědičnosti jako:

struct Email { property Data; Email(string data) : Data(data) { } virtual string opening() { return "Hello,\n"; } virtual string sign() { return "\nJan Turon\n\n"; } }; struct InformalEmail : public Email { InformalEmail(string data) : Email(data) { } string opening() { return "Hey,\n"; } }; struct FormalEmail : public Email { FormalEmail(string data) : Email(data) { } string sign() { return "\nBest Regards\nJan Turon\n\n"; } };

Potom lze vytvořit šablonovou metodu, které e-mail sestaví z objektu typu Email, který se jí předá:

struct TemplateEmail { static string Compose(Email* content) { string result = content->opening(); result+= content->Data; result+= content->sign(); delete content; return result; } };

Následně lze tvořit formální a neformální e-maily prostou parametru metody Compose:

int main() { string data = "I am glad to know it."; cout << TemplateEmail::Compose(new InformalEmail(data)); cout << TemplateEmail::Compose(new FormalEmail(data)); }