SWI041: Návrhové vzory (Design Patterns) JAK se to obvykle dlá
Zdroje: použity vzory GoF (Gamma, Helm, Johnson, Vlisidess: Design Patterns - The Elements of reusable objectoriented software. 1995), Tomáš Richta (Návrhové vzory I., FEL 2005), Petr Šlégr (Návrhové vzory II., FEL 2005) SWI041 - Návrhové vzory 2
Nejprve trochu kontroly Stav projekt
Co to je návrhový vzor? Christopher Alexander: Každý vzor popisuje asto se vyskytující problém a poté popisuje jádroešení tohoto problému tak, aby bylo možno toto ešení opakovan využívat, bez toho, že bychom stejnou vc dlali dvakrát". Pestože se tato definice týká návrhu budov, totéž platí pro návrhové vzory pi tvorb program. ešení je zde vyjádeno pomocí potebných objekt a zpsobu jejich komunikace. SWI041 - Návrhové vzory 4
Typy vzor Analytické vzory úetnictví Architektonické vzory Klient/Server, ti vrstvy, Broker, Model-View- Controller (MVC) Návrhové vzory základní - tvorba, struktura, chování (GoF) paralelní (producent-konzument), reálný as, testovací,... Programovací vzory, konvence SWI041 - Návrhové vzory 5
Obecnéásti návrhových vzor Jméno vzoru Popis problému Popisešení Dsledky použití SWI041 - Návrhové vzory 6
Jméno vzoru Termín, pes který se na vzor odvoláváme. Aby se v katalogu vzor dobe a intuitivn hledalo, je volba jména dležitá a obtížná. P.: Proxy, Iterator SWI041 - Návrhové vzory 7
Popis problému pro vzor Vyjaduje situaci, kde se použití vzoru hodí. Mže se stanovit píkladem, seznamem podmínek, které musí platit, apod. SWI041 - Návrhové vzory 8
P: Návrhový vzor Proxy Deklarace zámru: pokud potebujeme zástupce objektu, nebo vlastní objekt je nkde jinde, je tžko pístupný, má být chránn,... Motivaní píklad: editor dokumentu by ml umt pracovat s obrázky, ale zobrazení obrázku je nároné -asto postaí náhradník SWI041 - Návrhové vzory 9
Popisešen ení pro vzor Popisuje elementy použité piešení a jejich vztahy. Nejedná se o konkrétní implementaci, nebo vzor je pouze šablonou pro ešení. SWI041 - Návrhové vzory 10
Struktura vzoru Proxy Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 11
Dsledky použit ití vzoru Rozmanité dsledky, které s sebou použití vzoru pináší - nap. asové a prostorové nároky. Poslouží dobe i pi výbru alternativ. SWI041 - Návrhové vzory 12
Píklad použit ití vzoru Proxy Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 13
Píbuzné strukturáln lní vzory Proxy zastupuje objekt a poskytuje stejné rozhranní jako on Adapter mní rozhranní, které objekt poskytuje Dekorátor nco pidává SWI041 - Návrhové vzory 14
SWI041 - Návrhové vzory 15
Kategorie návrhových vzor Vzory pro vytváení a manipulaci sreprezentací informace (nap. Abstract Factory, Proxy) Vzory strukturální vyjadující strukturu implementace (nap. Adapter, Composite) Vzory pro chování (nap. Iterátor) SWI041 - Návrhové vzory 16
Taxonomie návrhových n vzor Tvorba Struktura Chování Statické Tovární metoda Adaptér (tídní) Šablonová metoda Dynamické Singleton Adaptér (instanní), Kompozice Strategie SWI041 - Návrhové vzory 17
Problém Je teba, aby v aplikaci existovala pouze jedna instance njaké tídy. Jak to zajistit? SWI041 - Návrhové vzory 18
Singleton SWI041 - Návrhové vzory 19
Singleton Vlastnosti: konkrétní typ poskytnuté instance lze urit za bhu poskytovanou instanci lze mnit bez zmn klientského kódu snadná zmna logiky tvorby - nap. povolení více instancí Píklad v J2SE: java.lang.runtime Související vzory: Null Object/Objekt null Object Pool SWI041 - Návrhové vzory 20
Problém Uritáást innosti (provádného algoritmu) je stejná u rzných tíd, ale bázová tída nezná odlišné chování svých potenciálních podtíd SWI041 - Návrhové vzory 21
Píklad: komunikaní systém m (chat) Server pijímá rzné typy zpráv a podle nich provádí rzné akce. Server pracuje podle tohoto schématu: kontrola identity a oprávnní zaslat danou zprávu provedení akce a píprava odpovdi odeslání odpovdi a záznam do logu Kroky 1. a 3. jsou stejné, krok 2. se bude lišit pro každý typ zprávy. SWI041 - Návrhové vzory 22
Template Method (šablonová metoda) Definuje kostru algoritmu Specifikaci nkterých krok nechává na podtídách Umožuje modifikovat nkteré kroky algoritmu bez zmny jeho struktury Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 23
Vzor: : Builder Deklarace zámru: oddlení konstrukce složitého objektu od jeho reprezentace pokud má být algoritmus pro vytváení složitého objektu nezávislý na vytváeníástí pokud lze objekt reprezentovat rznými zpsoby Motivaní píklad: editor dokumentu v RTF by ml umt pracovat s rznými reprezentacemi textu (ASCII, TeX, ) SWI041 - Návrhové vzory 24
Struktura vzoru Builder Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 25
Píklad použit ití vzoru Builder Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 26
Participanti Builder (TextConverter) specifikuje abstraktní interface pro vytváeníástí objekt typu Product. ConcreteBuilder (ASCIIConverter, TeXConverter, TextWidgetConverter) kontruuje a sestavujeásti - implementuje interface tídy Builder udržuje si vytvoenou reprezentaci poskytuje služby pro vyzvednutí produktu (GetASCIIText, GetTextWidget,...) SWI041 - Návrhové vzory 27
Participanti (pokra.) Director (RTFReader) konstruuje objekty pomocí služeb tídy Builder Product (ASCIIText, TeXText, TextWidget) reprezentuje složitý objekt, který je konstruován, tída ConcreteBuilder vytváí konkrétní vnitní reprezentaci zahrnuje tídy pro definiciástí a služby pro konstrukci celku SWI041 - Návrhové vzory 28
Kolaborace pi použit ití Builder Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 29
Vzor: Iterator (Cursor) Deklarace zámru: pro sekvenní pístup ke složkám složeného objektu bez ohledu na reprezentaci - pokud má být procházen seznam aniž se zabýváme jeho reprezentací (uniformní pístup pro traverzování agregovaných struktur) Motivaní píklad: sekvenní prchod seznamy SWI041 - Návrhové vzory 30
Struktura pro Iterator Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 31
Píklad použit ití Iterator Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 32
Participanti Iterator definuje služby pro pístup k elementm ConcreteIterator implementuje služby tídy Iterator udržuje si informace o aktuální poloze Aggregate definuje služby pro vytváení objet typu Iterator ConcreteAggregate implementuje služby pro tídu Aggregate SWI041 - Návrhové vzory 33
Implementace template <class Item> class List { public: List(long size = DEFAULT_LIST_CAPACITY); //... }; long Count() const; Item& Get(long index) const; SWI041 - Návrhové vzory 34
Implementace (pokra.) template <class Item> class Iterator { public: virtual void First() = 0; virtual void Next() = 0; virtual bool IsDone() const = 0; virtual Item CurrentItem() const = 0; protected: Iterator(); }; SWI041 - Návrhové vzory 35
Implementace (pokra.) template <class Item> class ListIterator : public Iterator<Item> { public: ListIterator(const List<Item>* alist); virtual void First(); virtual void Next(); virtual bool IsDone() const; virtual Item CurrentItem() const; private: const List<Item>* _list; long _current; }; SWI041 - Návrhové vzory 36
Implementace (pokra.) template <class Item> ListIterator<Item>::ListIterator ( const List<Item>* alist ) : _list(alist), _current(0) { } SWI041 - Návrhové vzory 37
Implementace (pokra.) template <class Item> void ListIterator<Item>::First () { _current = 0; } template <class Item> void ListIterator<Item>::Next () { _current++; } SWI041 - Návrhové vzory 38
Vzor: : Interpret Deklarace zámru: máme zadánu gramatiku jazyka, jehož vty chceme interpretovat Motivaní píklad: hledání vzorku zadaného regulárním výrazem v etzci (známe gramatiku regulárního výrazu) SWI041 - Návrhové vzory 39
Struktura vzoru Interpret globální kontext Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 40
Gramatika pro regulárn rní výraz expression ::= literal alternation sequence repetition '(' expression ')' alternation ::= expression ' ' expression sequence ::= expression '&' expression repetition ::= expression '*' literal ::= 'a' 'b' 'c'... { 'a' 'b' 'c'... }* SWI041 - Návrhové vzory 41
Interpret pro reg. výrazy Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 42
Reprezentace vzorku: raining & (dogs cats) * Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 43
Jiný píklad: Booleovské výrazy BooleanExp ::= VariableExp Constant OrExp AndExp NotExp '(' BooleanExp ')' AndExp ::= BooleanExp 'and' BooleanExp OrExp ::= BooleanExp 'or' BooleanExp NotExp ::= 'not' BooleanExp Constant ::= 'true' 'false' VariableExp ::= 'A' 'B'... 'X' 'Y' 'Z' SWI041 - Návrhové vzory 44
Tída BooleanExp class BooleanExp { public: BooleanExp(); virtual ~BooleanExp(); virtual bool Evaluate(Context&) = 0; virtual BooleanExp* Replace(const char*, BooleanExp&) = 0; virtual BooleanExp* Copy() const = 0; }; SWI041 - Návrhové vzory 45
Tída Context class Context { public: bool Lookup(const char*) const; void Assign(VariableExp*, bool); }; SWI041 - Návrhové vzory 46
Tída VariableExp class VariableExp : public BooleanExp { public: VariableExp(const char*); virtual ~VariableExp(); virtual bool Evaluate(Context&); virtual BooleanExp* Replace(const char*, BooleanExp&); virtual BooleanExp* Copy() const; private: char* _name; }; SWI041 - Návrhové vzory 47
Vzor: : Abstract factory (Kit) Deklarace zámru: interface pro vytváení kolekcí objekt bez podrobné specifikace jejich struktury Motivaní píklad: SWI041 - Návrhové vzory 48
Abstract factory (stavebnice( stavebnice) Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 49
Píklad použit ití Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 50
Vzor: : Factory method (virtu( virtuální konstruktor) Deklarace zámru: interface pro vytváení a manipulaci s objekty, jejichž konkrétní reprezentaci neznáme SWI041 - Návrhové vzory 51
Struktura pro Factory method Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 52
Píklad použit ití Factory method Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 53
SWI041 - Návrhové vzory 54
Pehled vzor Abstract Factory interface pro vytváení sady objekt, bez specifikace konkrétní tídy Adapter pevádí interface tídy na interface oekávaný klientem - umožuje spolupráci nekomatibilních tíd Bridge oddluje abstrakci od implementace, takže se mohou nezávsle mnit SWI041 - Návrhové vzory 55
Pehled vzor Builder oddluje konstrukci složeného objektu od jeho reprezentace, takže stejný proces mže vytváet rzné reprezentace Chain of Responsibility umožuje propojení zdroje požadavku s píjemcem tak, že dává více objektm šanci požadavek zpracovat. Zetzí píjemce a pedává požadavek mezi nimi. SWI041 - Návrhové vzory 56
Pehled vzor Command zapouzduje požadavek jako objekt, a tím umožuje parametrizovat klienty s rznými požadavky, frontami, žurnály Composite sestavuje objekt do stromové struktury aby reprezentoval vztah celek-ást. Umožuje pracovat s celkem a jehoástmi uniformním zpsobem SWI041 - Návrhové vzory 57
Pehled vzor Decorator dynamicky pidává odpovdnost, pružná alternativa pro rozšiování fuknosti (alternativa k podtídám) Facade poskytuje unifikovaný interface pro sadu nástroj - podsystém. Poskytuje interfacel vyšší úrovn tak, že použití podsystém je jednodušší. SWI041 - Návrhové vzory 58
Pehled vzor Factory Method definuje interface pro vytváení objektu, ale ponechává na podsystémech rozhodnutí, které tídy použijí (jakou instanci) Flyweight umožuje podporu efektivního sdílení velkých sad objekt Interpreter vychází z reprezentace gramatiky jazyka, která umožuje interpretaci vt jazyka SWI041 - Návrhové vzory 59
Pehled vzor Iterator poskytuje sekvenní pístup k sad element agregovaných objekt bez znalosti reprezentace sady Mediator definuje object, který zapouzduje zpsob jak spolu objekty komunikují - místo aby komunikovaly pímo SWI041 - Návrhové vzory 60
Pehled vzor Memento bez porušení pravidla zapouzdení umožuje zapamatování stavu, do kterého se objekt mže pozdji vrátit Observer definuje vztah 1:N mezi objekty tak, že pokud jeden objekt zmní stav, všechny objekty na nm závislé jsou na to upozornny a automaticky poopraveny SWI041 - Návrhové vzory 61
Pehled vzor Prototype specifikuje sadu objekt potebných pro vytvoení instance prototypu a pro kopírování tohoto prototypu Proxy poskytuje zástupce pro ízení pístupu k objektu Singleton zajišuje,a by tída mla pouze jednu instanci a poskytuje k ní globální pístup SWI041 - Návrhové vzory 62
Pehled vzor State umožuje objektu zmnu chování na základ zmny jeho stavu Strategy definuje rodinu algoritm, které jsou podobné a zamnitelné (umožuje zmnu algoritmu nezávisle na klientech) SWI041 - Návrhové vzory 63
Pehled vzor Template Method definuje kostru algoritmu operace, který pak komunikuje s podsystémy pi vlastnímešení - krokyešení se mohou mnit beze zmny kostry algoritmu Visitor reprezentuje operaci, která má být vykonána na elementech struktury objektu - návštvu struktury objektu SWI041 - Návrhové vzory 64
Píklad: Šablonová metoda 1 Vytvoíme tídu Message jako pedka pro všechny typy zpráv public abstract class Message { protected User sender; protected Message (User sender) { this.sender = sender; } } //... SWI041 - Návrhové vzory 65
Píklad: Šablonová metoda 2 Do tídy Message pidáme ty metody, jejichž implementace je známa a spolená všem podtídám /** Sends response back to the client and make log entry... */ private void sendresponse (String text) { } //... //... SWI041 - Návrhové vzory 66
Píklad: Šablonová metoda 3 Do tídy Message dále pidáme abstraktní metody, jejichž implementaci zajistí až podtídy /** Checks user's right to send this message */ public abstract boolean isallowedfor (User sender); /** Does message's job and return text to be sent to the client as response */ public abstract String process (); SWI041 - Návrhové vzory 67
Píklad: Šablonová metoda 4 Nakonec pidáme vlastní šablonovou metodu /** This is the TEMPLATE METHOD! It performs algorithm not defined fully in this class. */ public void dispatch () { } if (isallowedfor (sender)) { sendresponse (process ()); else { sendresponse ("Forbidden"); } SWI041 - Návrhové vzory 68
Píklad: Šablonová metoda 5 Struktura tídy Message (rekapitulace): private void sendresponse (String text) { } public abstract boolean isallowedfor (User sender); public abstract String process (); public void dispatch () { } SWI041 - Návrhové vzory 69
Píklad: Šablonová metoda 6 Tvorba podtídy: implementuje se pouze to specifické public class KickMessage extends Message { public boolean isallowedfor (User sender) { return sender.isadmin (); } } public String process() { // delete user from the room... return "User kicked from the room"; } SWI041 - Návrhové vzory 70
Šablonová metoda - diskuse Vlastnosti: nemnnáást algoritmu je implementována pouze jednou, podtídy implementují pro n specifické chování (statický vzor) Píklad v J2SE: vlastní chování tíd java.lang.threadi java.util.timertask se urí implementací metody run() v jejich podtíd. Související vzory: tovární metoda zvláštní pípad šablonové metody (tvorba objekt) strategie (viz dále) SWI041 - Návrhové vzory 71
Problém Je poteba mnit chování objektu za bhu Píklady: rzné zpsoby prezentace dat (nap. lámání textu, obarvování syntaxe v IDE) rzné zpsoby interpretace dat (nap. kalendá) SWI041 - Návrhové vzory 72
Píklad: výpis kalendáe kalendá se liší pro rzné národy a náboženství první den v týdnu mže být rzný množina svátk je odlišná potebujeme vypsat dny v týdnu s odlišením svátk SWI041 - Návrhové vzory 73
Vzor Strategy (strategie) Aka policy/postup Motivace: pro nkteréinnosti existuje mnoho algoritm, které ale nelze napevno implementovat (nap. jsou vhodné vždy jen pro uritou situaci) SWI041 - Návrhové vzory 74
Strategie Obrázek pevzat z [GoF] Vlastnosti (srv. šablonová metoda) pro stejná data se používají rzné algoritmy algoritmus je zapouzdený do samostatného objektu algoritmus lze dynamicky mnit za bhu SWI041 - Návrhové vzory 75
Píklad strategie 1 Definujeme rozhraní CalendarPrinter, které bude ídit výpis kalendáe public interface CalendarPrinter { public int getfirstdayofweek (); public boolean isholiday (int day, int month); } SWI041 - Návrhové vzory 76
Píklad strategie 2 Vytvoíme tídu Calendar s atributem printer a píslušnými metodami set a get (setery a getery) public class Calendar { protected printer = new DefaultCalendarPrinter (); public void setprinter (CalendarPrinter printer) { if (printer!= null) { this.printer = printer; } } public CalendarPrinter getprinter () { return printer; } } SWI041 - Návrhové vzory 77
Píklad strategie 3 Pidáme metodu využívající služby objektu CalendarPrinter public void printweek (int week) { } int start = printer.getfirstdayofweek (); for (...) { } if (printer.isholiday (day, month)) { //... } else { } //... SWI041 - Návrhové vzory 78
Píklad strategie 4 Základní implementace CalendarPrinter public class DefaultCalendarPrinter implements CalendarPrinter { public int getfirstdayofweek() { return 7; // nedele } } public boolean isholiday(int day, int month) { return false; // zadne svatky :-) } SWI041 - Návrhové vzory 79
Píklad strategie 5 Nyní vytvoíme (nebo uživatelé našeho API) další implementace public class FrenchCalendarPrinter implements CalendarPrinter { public int getfirstdayofweek() { return 1; // pondeli } } public boolean isholiday(int day, int month) { return day == 14 && month == 7; } SWI041 - Návrhové vzory 80
Strategie - diskuse Píklady v J2SE: Pi vytváení instancíjava.util.treeset lze specifikovat objekt typu java.util.comparator, který definuje zpsob uspoádání množiny. Pi vytváení instance tídy java.lang.thread lze specifikovat objekt typu java.lang.runnable s definovanou metodou run() (srv. pedefinování metody run() v potomkovi tídy Thread u šablonové metody). java.util.zip.checkedinputstream Související vzory: šablonová metoda statická verze vzoru strategie SWI041 - Návrhové vzory 81
Problém Tída má rozhraní pro tvorbu nových objekt. Konkrétní podtídy potebují vytváet velmi odlišné typy tchto objekt. Jak to udlat, když tída neví jaké objekty bude vytváet? SWI041 - Návrhové vzory 82
Factory Method/Tov /Tovární metoda Virtuální konstruktor Použití: editory vytváejí jednotným zpsobem rzné dokumenty (viz píklad) abstraktní (logické) objekty poskytují rznou grafickou reprezentaci (delegáta) SWI041 - Návrhové vzory 83
Factory Method/Tov /Tovární metoda Tovární metoda createdocument v tíd Editor vytváí rzné instance tídy Document podle toho, na které podtíd je vyvolána. SWI041 - Návrhové vzory 84
Factory Method/Tov /Tovární metoda Vlastnost: poskytuje rozhraní pro tvorbu objekt, ale volbu vytváeného objektu nechává na podtídách Píklad v J2SE: javax.swing.text.editorkit.createdefaultdocument () Související vzory: šablonová metoda (viz dále) delegát (Abstract) Factory samostatná tída (typu singleton) urená pro tvorbu objekt SWI041 - Návrhové vzory 85
Problém Na stavu jednoho objektu závisíada jiných objekt. Pi zmn stavu objektu potebují být závislé objekty automaticky vyrozumni. Jak toho docílit? SWI041 - Návrhové vzory 86
Observer/Pozorovatel Aka Dependents, Publish-Subscribe J2SE: Event Delegation Model Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 87
Observer/Pozorovatel Vlastnosti volné spojení tíd Observer a Subject hromadná komunikace (broadcast/vysílání) selektivní sledování zmn možnost odmítnutí zmn Píklady v J2SE: java.awt.* java.awt.event.* Component MouseListener JComponent PropertyChangeListener SWI041 - Návrhové vzory 88
Problém Chceme použít njakou užitenou tídu, která ale má jiné rozhraní, než oekáváme. Co s tím? SWI041 - Návrhové vzory 89
Adapter/Adaptér wrapper/obal Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 90
Adapter/Adaptér Tídní implementace: vícenásobná ddinost Instanní implementace: kompozice Obrázky pevzaty z [GoF] SWI041 - Návrhové vzory 91
Adapter/Adaptér Píklad v J2SE: java.awt.event.* MouseAdapter adaptér rozhraní MouseListener poskytuje prázdné implementace všech metod MouseListener Související vzory: delegát SWI041 - Návrhové vzory 92
Problém Máme hierarchicky organizovaný celek s jehožástmi chceme manipulovat jednotným zpsobem. Jak na to? SWI041 - Návrhové vzory 93
Composite/Kompozice Použití: grafická uživatelská rozhraní strukturované dokumenty (XML, HTML,...) stromov organizovaná data... Obrázek pevzat z [GoF] SWI041 - Návrhové vzory 94
Composite/Kompozice Vlastnosti: definuje spolené rozhraní pro objekty stromové hierarchie jednoduché použití klient se nestará, zda pracuje s celkem nebo ástí snadné rozšiování nové prvky automaticky fungují se starými klienty Píklad v J2SE: java.awt.* Component abstraktní komponenta Container abstraktní kontejner Button, Label konkrétní jednoduché objekty Panel, Window konkrétní složené objekty SWI041 - Návrhové vzory 95
The End