Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Vaše jistota na trhu IT Návrhové vzory Rudolf PECINOVSKÝ

Podobné prezentace


Prezentace na téma: "Vaše jistota na trhu IT Návrhové vzory Rudolf PECINOVSKÝ"— Transkript prezentace:

1 Vaše jistota na trhu IT Návrhové vzory Rudolf PECINOVSKÝ

2 ICZ Copyright © 2009, Rudolf Pecinovský 2 Stručný obsah ►00: Předehra00: Předehra ►01: První kontakt01: První kontakt ►02: Vzory řešící počet instanci02: Vzory řešící počet instanci ►03: Skrývání implementace03: Skrývání implementace ►04: Optimalizace rozhraní04: Optimalizace rozhraní ►05: Otevřenost variantním řešením05: Otevřenost variantním řešením ►06: Ochrana před rozrůstáním06: Ochrana před rozrůstáním ►07: Dodatečné úpravy07: Dodatečné úpravy

3 ICZ Copyright © 2009, Rudolf Pecinovský 3 Podrobný obsah1/2 ►00: Předehra00: Předehra ● Ohlédnutí do historie001 Ohlédnutí do historie ● Quo vadis programování?002 Quo vadis programování? ● Základní principy OOP003 Základní principy OOP ● Rozhraní004 Rozhraní ● Zapouzdření a skrývání implementace005 Zapouzdření a skrývání implementace ● Další užitečné zásady 006 Další užitečné zásady ►01: První kontakt01: První kontakt ● Jednoduchá tovární metoda (Simple factory method)011 Jednoduchá tovární metoda (Simple factory method) ● Neměnné objekty (Immutable objects)012 Neměnné objekty (Immutable objects) ● Přepravka (Crate)013 Přepravka (Crate) ● Služebník (Servant)014 Služebník (Servant) ● Prázdný objekt (Null Object)015 Prázdný objekt (Null Object) ►02: Vzory řešící počet instanci02: Vzory řešící počet instanci ● Společné vlastnosti020 Společné vlastnosti ● Knihovní třída (Library class, Utility)021 Knihovní třída (Library class, Utility) ● Jedináček (Singleton)022 Jedináček (Singleton) ● Výčtový typ (Enumeration)023 Výčtový typ (Enumeration) ● Fond (Pool)025 Fond (Pool) ● Originál (Original)024 Originál (Original) ● Muší váha (Flyweight)026 Muší váha (Flyweight) ►03: Skrývání implementace03: Skrývání implementace ● Zástupce (Proxy)031 Zástupce (Proxy) ● Příkaz (Command)032 Příkaz (Command) ● Iterátor (Iterator)033 Iterátor (Iterator) ● Stav (State)034 Stav (State) ● Šablonová metoda (Template Method)035 Šablonová metoda (Template Method)

4 ICZ Copyright © 2009, Rudolf Pecinovský 4 Podrobný obsah1/2 ►04: Optimalizace rozhraní04: Optimalizace rozhraní ● Fasáda (Facade)041 Fasáda (Facade) ● Adaptér (Adapter)042 Adaptér (Adapter) ● Strom (Composite)043 Strom (Composite) ►05: Otevřenost variantním řešením05: Otevřenost variantním řešením ● Tovární metoda (Factory method)051 Tovární metoda (Factory method) ● Prototyp (Prototype)052 Prototyp (Prototype) ● Stavitel (Builder)053 Stavitel (Builder) ● Abstraktní továrna (Abstract factory)054 Abstraktní továrna (Abstract factory) ►06: Ochrana před rozrůstáním06: Ochrana před rozrůstáním ● Dekorátor (Decorator) 061 Dekorátor (Decorator) ● Řetěz odpovědnosti (Chain of responsibility)062 Řetěz odpovědnosti (Chain of responsibility) ● Pozorovatel (Observer)063 Pozorovatel (Observer) ● Prostředník (Mediator)064 Prostředník (Mediator) ►07: Dodatečné úpravy07: Dodatečné úpravy ● Most (Bridge)071 Most (Bridge) ● Strategie (Strategy)072 Strategie (Strategy) ● MVC (Model – View – Controller)073 MVC (Model – View – Controller) ● Návštěvník (Visitor)074 Návštěvník (Visitor) ● Pamětník (Memento)075 Pamětník (Memento) ● Interpret (Interpreter)076 Interpret (Interpreter)

5 Vaše jistota na trhu IT 00 Předehra 00 ►Ohlédnutí do historie001Ohlédnutí do historie ►Quo vadis programování?002Quo vadis programování? ►Základní principy OOP003Základní principy OOP ►Rozhraní004Rozhraní ►Zapouzdření a skrývání implementace005Zapouzdření a skrývání implementace ►Další užitečné zásady006Další užitečné zásady

6 Vaše jistota na trhu IT 01 První kontakt01 ►Jednoduchá tovární metoda (Simple factory method)011Jednoduchá tovární metoda (Simple factory method) ►Neměnné objekty (Immutable objects)012Neměnné objekty (Immutable objects) ►Přepravka (Crate, Transport Object)013Přepravka (Crate, Transport Object) ►Služebník (Servant)014Služebník (Servant) ►Prázdný objekt (Null Object)015Prázdný objekt (Null Object)

7 ICZ Copyright © 2009, Rudolf Pecinovský 7 Návrhové vzory – Design Patterns ►Programátorský ekvivalent matematických vzorečků ►Výhody: ● Zrychlují návrh (řešení se nevymýšlí, ale jenom použije) ● Zkvalitňují návrh ● Jsou ověřené, takže výrazně snižují pravděpodobnost potenciálních chyb typu na něco jsme zapomněli ● Zjednodušují a zpřesňují komunikaci mezi členy týmu (větou, že diskriminant je záporný, řeknu znalým jednoduše řadu věcí, které bych musel jinak složitě vysvětlovat) ►Znalost návrhových vzorů patří k povinné výbavě současného objektově orientovaného programátora

8 Vaše jistota na trhu IT Jednoduchá tovární metoda010 ►Jednoduchá (někdo používá termín statická) tovární metoda je zjednodušenou verzí návrhového vzoru Tovární metoda. Definuje statickou metodu nahrazující konstruktor. Používá se všude tam, kde potřebujeme získat odkaz na objekt, ale přímé použití konstruktoru není z nejrůznějších příčin optimálním řešením. Obsah

9 ICZ Copyright © 2009, Rudolf Pecinovský 9 Charakteristika ►Speciální případ obecné tovární metody ►Náhražka konstruktoru v situacích, kdy potřebujeme funkčnost nedosažitelnou prostřednictvím konstruktorů ►Kdy po ni sáhneme ● Potřebujeme rozhodnout, zda se opravdu vytvoří nová instance ● Potřebujeme vracet instance různých typů ● Potřebujeme provést nějakou akci ještě před tím, než se zavolá rodičovský konstruktor ● Potřebujeme více verzí se stejnými sadami parametrů (tovární metody mohou mít různé názvy)

10 ICZ Copyright © 2009, Rudolf Pecinovský 10 Implementace ►Statická metoda vracející instanci daného typu ►Nemusí vracet vlastní instanci, ale může si vybrat potomka, jehož instanci následně vrátí ►Jmenné konvence ● getInstance ● getXXX, kde XXX je název vraceného typu ● valueOf ● Naznačující účel probablePrime

11 ICZ Copyright © 2009, Rudolf Pecinovský 11 Příklad: AČlověk public static AČlověk getČlověk() { switch ( index++ % 3 ) { case 0: return new Lenoch(); case 1: return new Čilouš(); case 2: return new Pracant(); default: throw new RuntimeException( "Špatně definované maximum" ); } ►Tovární metoda může rozhodnout o skutečném typu vráceného objektu

12 ICZ Copyright © 2009, Rudolf Pecinovský 12 Příklad ze standardní knihovny – Integer private static class IntegerCache { private IntegerCache(){} static final Integer cache[] = new Integer[-(-128) ]; static { for (int i = 0; i < cache.length; i++) cache[i] = new Integer(i - 128); } public static Integer valueOf(int i) { final int offset = 128; if (i >= -128 && i <= 127) { // must cache return IntegerCache.cache[i + offset]; } return new Integer(i); } Pomocná vnořená třída; zásobník instancí Tovární metoda pro získání instance

13 Vaše jistota na trhu IT Neměnné objekty (Immutable objects )012 ►Neměnný objekt je hodnotový objekt, u nějž není možno změnit jeho hodnotu. Obsah

14 ICZ Copyright © 2009, Rudolf Pecinovský 14 Primitivní a objektové typy Java pro zvýšení efektivnosti dělí datové typy na: ►Primitivní někdo je označuje jako hodnotové, protože se u nich pracuje přímo s hodnotou daného objektu (číslo, znak, logická hodnota) ►Objektové někdo je označuje za referenční, protože se u nich pracuje pouze s odkazem („referencí“) na objekt ● Označování odkazových typů jako referenční je z jazykového hlediska stejná chyba, jako překládat control (řídit)  kontrolovat (check) ● Reference (česky) = zpráva, dobrozdání, doporučení, posudek ●Viz Akademický slovník cizích slov, ISBN , str. 652 ● Reference (anglicky) = zmínka, narážka, odkaz, vztah, … ●Viz Velký anglicko-český slovník, nakl. ČSAV , str ►Dělení na hodnotové a odkazové není terminologicky vhodné protože objektové typy dále dělíme na hodnotové a odkazové

15 ICZ Copyright © 2009, Rudolf Pecinovský 15 Dělení objektových datových typů ►Odkazové objektové datové typy (reference object data types) ● Neuvažujeme o hodnotách, objekt představuje sám sebe, nemá smysl hovořit o ekvivalenci dvou různých objektů ● Příklady ●Geometrické tvary ●Vlákna ►Hodnotové objektové datové typy (value object data types) ● Objekt zastupuje nějakou hodnotu ● Objekty se stejnou hodnotou se mohou vzájemně zastoupit => má smysl hovořit o jejich ekvivalenci ● Příklady ●Obalové typy, zlomky, velká čísla a další matematické objekty ●Barvy, časy, data ● Překrývají metody equals(Object) a hashCode() ●Tyto metody je vždy vhodné překrýt obě, jinak hrozí problémy

16 Terminologický guláš na platformě.NET ►Platforma.NET používá vlastní terminologie – jako hodnotové typy označují datové typy, u nichž je přiřazení realizováno kopírováním obsahu paměti přiřazené objektu ● Takovéto datové typy budeme označovat jako kopírované ►„Hodnotový“ datový typ v terminologii.NET vůbec nemusí reprezentovat nějakou hodnotu ►Kopírované objektové datové typy má i C++, z historických důvodů pro ně nezavádělo název ►Moderní jazyky kopírované datové typy většinou nepoužívají ●.NET je zavedl aby vyšel vstříc zvyklostem programátorů v C++ ● Důvod je podobný jako důvod zavedení primitivních typů v Javě ICZ Copyright © 2009, Rudolf Pecinovský 16

17 ICZ Copyright © 2009, Rudolf Pecinovský 17 Dělení hodnotových objektů ►Proměnné ● Jejich hodnota se může v průběhu života změnit ● Nesmějí se používat v některých situacích ►Neměnné ● Hodnotu, která jim byla přiřazena „při narození“ zastupují až do své „smrti“ ● Chovají se obdobně jako hodnoty primitivních typů a také je s nimi možno obdobně zacházet ● Metody, které mají měnit hodnotu objektu, musejí vracet jiný objekt s touto změněnou hodnotou ►Všechny hodnotové typy bychom měli definovat jako neměnné ● Neplatí jen pro Javu, ale i pro jazyky, které umožňují pracovat přímo s objekty a ne jenom s odkazy (C++, C # )

18 ICZ Copyright © 2009, Rudolf Pecinovský 18 Důsledky proměnnosti objektů ►Hodnota objektu se může změnit uprostřed výpočtu (jako kdyby se z pětek staly šestky) ►Se změnou hodnoty objektu se obecně mění i jeho hash-code => ►Uložíme-li objekt do kontejneru implementovaného pomocí hashové tabulky a po změně hodnoty jej tam už nenajdeme ►Používání proměnných hodnotových objektů výrazně snižuje robustnost a bezpečnost programů ►Proměnnost datových typů je nebezpečná zejména v programech, v nichž běží souběžně několik vláken ● Jazyky určené pro paralelní programování neměnné typy silně protěžují

19 ICZ Copyright © 2009, Rudolf Pecinovský 19 Doporučené k použití ►Neměnné musí zůstávat jen atributy, jejichž hodnoty používají metody equals(Object) a hashCode() ►Atributy neovlivňující výsledky těchto metod se mohou měnit, protože na nich hodnota instance nezávisí ►Příklad: Atributy počítající počet použití dané instance, počet volání některé metody atd. ►V hodnotových třídách by měly všechny „změnové metody“ vytvářet nové instance Objektové OdkazovéHodnotové ProměnnéNeměnné Datové typy Primitivní

20 ICZ Copyright © 2009, Rudolf Pecinovský 20 Příklad: Zlomek public class Zlomek extends Number { private final int c; //čitatel private final int j; //jmenovatel; public Zlomek plus(Zlomek z) { //this. return new Zlomek( this.c*z.j + z.c*j, this.j*z.j ); } public Zlomek krát(Zlomek z) { return new Zlomek( c * z.c, j * z.j ); } //...

21 Vaše jistota na trhu IT Přepravka (Crate, Transport Object) 013 ►Vzor Přepravka využijeme při potřebě sloučení několika samostatných informací do jednoho objektu, prostřednictvím nějž je pak možno tyto informace jednoduše ukládat nebo přenášet mezi metodami. Obsah

22 ICZ Copyright © 2009, Rudolf Pecinovský 22 Motivace ►Některé vlastnosti sestávají z více jednoduchých hodnot ● Pozice je definována jednotlivými souřadnicemi ►Při nastavování takových hodnot se používá více parametrů ● Příklad: setPozice(int x, int y) ►Takovéto hodnoty se špatně zjišťují, protože Java neumožňuje vrácení několika hodnot současně ►Možnosti: ● Zjišťovat každou složku zvlášť ( getX() + getY() ) ● Definuje se speciální třída, jejíž instance budou sloužit jako přepravky pro přenášení dané sady hodnot ►Druhou možnost doporučuje návrhový vzor Přepravka ►V anglické literatuře bývá označován nebo Transport Object ● Eckel jej v „Thinking in Patterns“ označuje jako Messenger

23 ICZ Copyright © 2009, Rudolf Pecinovský 23 Vlastnosti přepravky ►Přepravka je objekt určený k uložení skupiny údajů „pod jednu střechu“ a jejich společnému transportu ►Přepravku řadíme mezi kontejnery = objekty určené k uložení jiných objektů ►Oproti standardům definuje své atributy jako veřejné, aby tak zjednodušila a zefektivnila přístup k jejich hodnotám ►Aby nebylo možno atributy nečekaně měnit, definuje je jako konstantní ►Velmi často pro ni definujeme pouze konstruktor s parametrem pro každý atribut, ale žádné metody ►V řadě případů však přepravky definují přístupové metody, ale i řadu dalších užitečných metod

24 ICZ Copyright © 2009, Rudolf Pecinovský 24 Definice přepravky Pozice public class Pozice { public final int x; public final int y; public Pozice( int x, int y ) { this.x = x; this.y = y; }

25 ICZ Copyright © 2009, Rudolf Pecinovský 25 Použití přepravky Pozice public class Světlo { private static final Barva ZHASNUTÁ = Barva.ČERNÁ; private final Elipsa žárovka; private final Barva barva; //... Konstruktory a dříve definované metody public Pozice getPozice() { return new Pozice( žárovka.getX(), žárovka.getY() ); } public void setPozice( int x, int y ) { žárovka.setPozice( x, y ); } public void setPozice( Pozice p) { žárovka.setPozice( p.x, p.y ); } Převádí akci na svoji přetíženou verzi

26 Vaše jistota na trhu IT Služebník (Servant)014 ►Návrhový vzor Služebník použijeme v situaci, kdy chceme skupině tříd nabídnout nějakou další funkčnost, aniž bychom zabudovávali reakci na příslušnou zprávu do každé z nich. ►Služebník je třída, jejíž instance (případně i ona sama) poskytují metody, které si vezmou potřebnou činnost (službu) na starost, přičemž objekty, s nimiž (nebo pro něž) danou činnost vykonávají, přebírají jako parametry. Obsah

27 ICZ Copyright © 2009, Rudolf Pecinovský 27 Motivace ►Několik tříd potřebuje definovat stejnou činnost a nechceme definovat na několika místech stejný kód ►Objekt má úkol, který naprogramovat buď neumíme, nebo bychom jej sice zvládli, ale víme, že je úloha již naprogramovaná jinde ►Řešení: Definujeme či získáme třídu, jejíž instance (služebníci) budou obsluhovat naše instance a řešit úkoly místo nich ● Řešení pak bude na jednom místě a bude se snáze spravovat ►Postup se hodí i když připravujeme řešení, které chceme definovat dostatečně obecné, aby je mohli používat všichni, kteří je budou v budoucnu potřebovat, a přitom nevíme, kdo budou ti potřební

28 ICZ Copyright © 2009, Rudolf Pecinovský 28 Implementace ►Služebník nepracuje sám, ale komunikuje s obsluhovanými instancemi ►Aby mohl instance bezproblémově obsluhovat, klade na ně požadavky, co všechno musejí umět ►Služebník proto: ● Definuje rozhraní ( interface ), v němž deklaruje své požadavky ● Jeho obslužné metody budou jako své parametry akceptovat pouze instance deklarovaného rozhraní ►Instance, která chce být obsloužena: ● Musí být instancí třídy implementující dané rozhraní, aby se mohla vydávat za jeho instanci ● Implementací rozhraní deklaruje, že umí to, co od ní služebník k její plnohodnotné obsluze požaduje

29 ICZ Copyright © 2009, Rudolf Pecinovský 29 Klient posílá zprávu obsluhované instanci a ta předá požadavek služebníku, který jej realizuje; klient nemusí o služebníku vědět Služebník – diagramy tříd Klient posílá zprávu přímo služebníku a v parametru mu současně předává instanci, kterou má obsloužit

30 ICZ Copyright © 2009, Rudolf Pecinovský 30 Příklad 1: Plynule posuvné objekty ►Objekty projektu Tvary se umí přesouvat pouze skokem ►Pokud bychom chtěli, aby se přesouvaly plynule, museli bychom do každého z nich přidat příslušné metody, které by však byly u všech tříd téměř totožné ►Seženeme si služebníka – instanci třídy Přesouvač ►Tito služebníci vyžadují od obsluhovaných objektů implementaci rozhraní IPosuvný deklarujícího metody: ● Pozice getPozice(); ● void setPozice( Pozice pozice ); ● void setPozice( int x, int y ); ►Zato nabízí možnost volat metody: ● void přesunO ( IPosuvný ip, int dx, int dy ); ● void přesunNa( IPosuvný ip, int x, int y ); ● void přesunNa( IPosuvný ip, Pozice pozice );

31 ICZ Copyright © 2009, Rudolf Pecinovský 31 Příklad 2: Blikající světlo ►Chceme po instancích třídy Světlo, aby uměly blikat zadanou dobu nezávisle na jiné činnosti ►Cyklus je nepoužitelný, protože po dobu jeho provádění ostatní činnosti stojí ● Takto není možno naprogramovat ukazatel směru jedoucího auta ►Využijeme služeb instancí třídy Opakovač, jejichž metody umějí opakovat klíčové činnosti svých parametrů ►Opakovač od obsluhovaných vyžaduje, aby implementovali rozhraní IAkční s metodou akce(), kterou bude opakovač zadaný-počet-krát opakovat ►Demo: D03-2: Blikání světlaD03-2: Blikání světla

32 Vaše jistota na trhu IT Prázdný objekt (Null Object)015 ►Prázdný objekt je platný, formálně plnohodnotný objekt, který použijeme v situaci, kdy by nám použití klasického prázdného ukazatele null přinášelo nějaké problémy – např. by vyžadovalo neustále testování odkazuj na prázdnost nebo by vedlo k vyvolání výjimky NullPointerException. Obsah

33 ICZ Copyright © 2009, Rudolf Pecinovský 33 Motivace ►Vrací-li metoda v nějaké situaci prázdný odkaz ( null ), musí volající metoda tuto možnost kontrolovat, než získaný odkaz použije ►Vrácením odkazu na plnohodnotný objekt umožníme zrušit tyto testy ►Příklady: ● Žádná barva ● Žádný směr ● Prázdný iterovatelný objekt – viz další stránka ● Třída java.util.Collections ● public static final Set emptySet() ● public static final List emptyList() ● public static final Map emptyMap()

34 ICZ Copyright © 2009, Rudolf Pecinovský 34 Příklad: Směr8 public enum Směr8 { //== HODNOTY VÝČTOVÉHO TYPU ============ VÝCHOD ( 1, 0, "S" ), SEVEROVÝCHOD( 1, -1, "SV" ), SEVER ( 0, -1, "S" ), SEVEROZÁPAD ( -1, -1, "SZ" ), ZÁPAD ( -1, 0, "Z" ), JIHOZÁPAD ( -1, 1, "JZ" ), JIH ( 0, 1, "J" ), JIHOVÝCHOD ( 1, 1, "JV" ), ŽÁDNÝ ( 0, 0, ), ; //... zbytek definice

35 ICZ Copyright © 2009, Rudolf Pecinovský 35 Příklad: PrázdnýIterátor public class PrázdnýIterátor implements Iterator { public boolean hasNext() { return false; } public next() { throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException(); }

36 ICZ Copyright © 2009, Rudolf Pecinovský 36 Příklad: PrázdnýIterable public class PrázdnýIterable implements Iterable { private static final PrázdnýIterable jedináček = new PrázdnýIterable(); public static PrázdnýIterable getInstance() { return jedináček; } public Iterator iterator() { return PrázdnýIterátor.getInstance(); }

37 Vaše jistota na trhu IT 02 Vzory řešící počet instancí 02 ►Společné vlastnosti020Společné vlastnosti ►Knihovní třída (Library class, Utility)021Knihovní třída (Library class, Utility) ►Jedináček (Singleton)022Jedináček (Singleton) ►Výčtový typ (Enumeration)023Výčtový typ (Enumeration) ►Fond (Pool)025Fond (Pool) ►Originál (Original)024Originál (Original) ►Muší váha (Flyweight)026Muší váha (Flyweight) Obsah

38 Vaše jistota na trhu IT Společné vlastnosti vzorů řešících problematiku počtu instancí020 Obsah

39 ICZ Copyright © 2009, Rudolf Pecinovský 39 Motivace ►Zabezpečit dodržení zadaných pravidel pro vznik a případný zánik instancí ►Aby mohla třída za něco ručit, musí se o vše postarat sama a nenechat si do toho mluvit ►Třída poskytuje globální přístupové body k vytvořeným instancím – tovární metody ● Rozhodnou zda vytvořit instanci či vrátit některou starší ● Vyberou třídu, jejíž instance se vytvoří ● Mohou před vlastním vytvořením instance provést nějaké pomocné akce

40 ICZ Copyright © 2009, Rudolf Pecinovský 40 Soukromý konstruktor ►Potřebují mít „v rukou“ vytváření instancí, takže nesmí nikomu umožnit, aby je vytvářel po svém ►Konstruktor vytvoří při každém zavolání novou instancí => je třeba jej znepřístupnit ►Definují konstruktor jako soukromý, a zveřejní místo něj tovární metodu ● Nikdo nemá šanci vytvořit instanci bez vědomí mateřské třídy ● Třída může rozhodovat, zda se vytvoří nová instance, nebo zda se použije existující ● Existence konstruktoru zamezí překladači vytvořit implicitní => je třeba jej vytvořit, i když žádný nechceme

41 ICZ Copyright © 2009, Rudolf Pecinovský 41 Problémy se serializovatelností ►Načtení objektu z proudu obchází konstruktor ►Je třeba zabezpečit, aby i při načtení z proudu udržela třída kontrolu nad tvorbou svých instancí ►Třída musí rozhodnout, zda místo načteného objektu vrátí některý z existujících, anebo opravdu vytvoří nový ►Řešení závisí na realizaci ● Knihovny proudů ● Procesu serializace

42 Vaše jistota na trhu IT Knihovní třída (Library class, Utility)021 ►Knihovní třída slouží jako obálka pro soubor statických metod. Protože k tomu nepotřebuje vytvářet instance, je vhodné jejich vytváření znemožnit. Obsah

43 ICZ Copyright © 2009, Rudolf Pecinovský 43 Charakteristika ►Slouží jako kontejner na metody, které nepotřebují svoji instanci ● Matematické funkce ● Pomocné funkce pro rodinu tříd ►Všechny metody jsou statické ►Nepotřebují instanci => neměly by ji ani umožnit vytvořit ● Definují soukromý konstruktor, aby místo něj nemohl překladač definovat vlastní verzi

44 ICZ Copyright © 2009, Rudolf Pecinovský 44 Příklady ► java.lang.Math ► java.lang.Runtime ► java.lang.System ► java.util.Arrays ► java.util.Collections

45 Vaše jistota na trhu IT Jedináček (Singleton)022 ►Jedináček specifikuje, jak vytvořit třídu, která bude mít nejvýše jednu instanci. Tato instance přitom nemusí být vlastní instancí dané třídy. Obsah

46 ICZ Copyright © 2009, Rudolf Pecinovský 46 Charakteristika ►Zabezpečuje vytvoření nejvýše jedné instance ● Tovární metoda vrací pokaždé odkaz na tutéž instanci jedináčka ►Většinou se vytváří instance vždy (tj. právě jedna), ale je-li její vytvoření drahé, lez použít odloženou inicializaci (je ale náročnější) ►Tovární metoda může vracet i instance potomků ● Je-li to účelné, může třída rozhodnout, zda nechá vytvořit instanci svoji či některého ze svých potomků ● Tovární metoda pak bude vracet odkaz na tu instanci, která byla při inicializaci vytvořena ►Příklady: Schránka (clipboard), Plátno

47 ICZ Copyright © 2009, Rudolf Pecinovský 47 Realizace ►Odkaz na jedináčka je uložen ve statickém atributu ►Není-li požadována odložená inicializace, lze atribut inicializovat již v deklaraci (nejlepší řešení) ►Je třeba zabezpečit, aby všechny objekty, které tato inicializace používá, byly již validní ►Odložená inicializace přináší problémy v programech, které používají vlákna či podprocesy ►Je třeba ošetřit neklonovatelnost a případnou serializaci

48 ICZ Copyright © 2009, Rudolf Pecinovský 48 Ukázka public class Jedináček { private static final Jedináček JEDINÁČEK = new Jedináček(); public static Jedináček getInstance() { return JEDINÁČEK; }

49 ICZ Copyright © 2009, Rudolf Pecinovský 49 Výhody oproti statickému atributu ►Jedináček: jediná instance třída je získávána voláním veřejné tovární metody ►Atribut: Odkaz na jedinou instanci je uložen ve veřejném statickém atributu ►Výhody atributu ● Trochu méně psaní ● Většinou nepatrně větší rychlost ►Výhody jedináčka ● Snazší dynamická kontrola nad poskytováním přístupu ● Otevřenější vůči případným budoucím úpravám (např. náhrada jedináčka fondem)

50 ICZ Copyright © 2009, Rudolf Pecinovský 50 Jednovláknová odložená inicializace public static Jedináček getInstance() { if (JEDINÁČEK == null) { JEDINÁČEK = new Jedináček(); } return JEDINÁČEK; }

51 ICZ Copyright © 2009, Rudolf Pecinovský 51 Problémy při více vláknech První vláknoDruhé vlákno Jedináček.getInstance() { if( JEDINÁČEK == null ) { Jedináček.getInstance() { if( JEDINÁČEK == null ) { JEDINÁČEK = new Jedináček(); } return JEDINÁČEK; } JEDINÁČEK = new Jedináček(); } return JEDINÁČEK; }

52 ICZ Copyright © 2009, Rudolf Pecinovský 52 Problémy při více vláknech První vláknoDruhé vlákno Jedináček.getInstance() { if( JEDINÁČEK == null ) { Jedináček.getInstance() { if( JEDINÁČEK == null ) { JEDINÁČEK = new Jedináček(); } return JEDINÁČEK; } JEDINÁČEK = new Jedináček(); } return JEDINÁČEK; }

53 ICZ Copyright © 2009, Rudolf Pecinovský 53 Možné řešení private static volatile Jedináček JEDINÁČEK = null; public static Jedináček getJedináček() { if (JEDINÁČEK == null ) { synchronized( Jedináček.class ) { if (JEDINÁČEK == null ) { JEDINÁČEK = new Jedináček(); } return JEDINÁČEK; }

54 ICZ Copyright © 2009, Rudolf Pecinovský 54 Současné doporučované řešení public class Jedináček { private Jedináček() { } public static Jedináček getInstance() { return Schránka.INSTANCE; } private static class Schránka { private static final Jedináček INSTANCE = new Jedináček(); }

55 Vaše jistota na trhu IT Výčtový typ (Enumeration)023 ►Výčtové typy slouží k definici skupin předem známých hodnot a k umožnění následné typové kontroly. Vedle klasických hodnotových výčtových typů umožňuje Java definovat i Funkční výčtové typy, u nichž se jednotlivé hodnoty liší reakcemi na zasílané zprávy. Obsah

56 ICZ Copyright © 2009, Rudolf Pecinovský 56 Charakteristika ►Předem pevně daný počet instancí s předem pevně danými hodnotami ►Ekvivalent enum v C++, ale s OO nadstavbou a důslednou typovou kontrolou ►Výhody ● Důsledná typová kontrola ● V kontejnerech instancí lze využít známý maximální počet ►Problémy ● Je třeba ošetřit serializovatelnost a klonovatelnost ● Standardní knihovna Javy ji řeší

57 ICZ Copyright © 2009, Rudolf Pecinovský 57 Implementace ►Sada statických atributů odkazujících na instance své třídy ►Atributy jsou inicializovány v deklaraci ►Jazyk často nabízí prostředky na efektivní použití v přepínačích a cyklech s parametrem ● Umí vrátit vektor seřazených hodnot ● Umí vrátit instanci se zadaným pořadím ● Umí vrátit pořadí zadané instance ve výčtu

58 ICZ Copyright © 2009, Rudolf Pecinovský 58 Syntaxe výčtových typů ►V definicích výčtových typů je klíčové slovo class nahrazeno slovem enum ►Za hlavičkou třídy následuje seznam hodnot daného typu ►Za čistým výčtem (jenom výčet bez metod) nemusí následovat středník; jakmile však výčet není osamocen, středník je nutný (raději psát vždy) ►Výčtový typ překladač přeloží stejně jako kdyby byl definován jako potomek třídy java.lang.Enum public enum Období { JARO, LÉTO, PODZIM, ZIMA; }

59 ICZ Copyright © 2009, Rudolf Pecinovský 59 Přeložený tvar čistého výčtu package výčty; public final class Období extends Enum { public static final Období JARO; public static final Období LÉTO; public static final Období PODZIM; public static final Období ZIMA; private static final Období $VALUES[]; static { JARO = new Období("JARO", 0); LÉTO = new Období("LÉTO", 1); PODZIM = new Období("PODZIM", 2); ZIMA = new Období("ZIMA", 3); $VALUES = new Období[] { JARO, LÉTO, PODZIM, ZIMA }; } public static final Období[] values() { return (Období[])((Období []) ($VALUES)).clone(); } public static Období valueOf(String name) { return (Období)Enum.valueOf(výčty.Období, name); } private Období(String s, int i) { super(s, i); } Pole hodnot daného typu Deklarace hodnot (veřejných konstant) daného typu Statický inicializační blok inicializující konstanty a pole s odkazy na ně Metoda vracející pole hodnot daného typu Metoda vracející hodnotu po zadání jejího názvu Soukromý konstruktor zabraňující vytváření dalších instancí

60 ICZ Copyright © 2009, Rudolf Pecinovský 60 Metody zděděné od třídy Enum ► String name() Vrátí název dané instance ► int ordinal() Vrátí pořadí deklarace dané instance (začíná se nulou) ► boolean equals(Object other) Vrací true je-li instance totožná s parametrem ► int compareTo(E o) Vrátí -1, 0 či +1 podle toho, je-li deklarace daná instance menší, rovna či větší než parametr (porovnává se ordinal ) ► E[] values() ► E valueOf(String name) Jsou zde uvedeny pro úplnost, nedědí se, dodá je překladač (viz předchozí snímek) Překrytá verze rodičovské metody (volá rodiče a přetypuje výsledek)

61 ICZ Copyright © 2009, Rudolf Pecinovský 61 „Chytřejší“ výčtové typy ►Často je výhodné, aby hodnoty výčtového typu vykazovaly jistou „dodatečnou inteligenci“ ►Výčtové typy nemusí být pouze čistým výčtem hodnot, jsou to standardní typy ● Mohou mít vlastní atributy a vlastnosti ● Mohou mít vlastní metody ● Mohou využívat konstruktoru s parametry ►Příklad: Směr8

62 ICZ Copyright © 2009, Rudolf Pecinovský 62 Vytváření instancí třídy Směr8 public enum Směr8 { //== HODNOTY VÝČTOVÉHO TYPU ================================================== VÝCHOD ( 1, 0, "V", "VYCHOD" ), SEVEROVÝCHOD( 1, -1, "SV", "SEVEROVYCHOD" ), SEVER ( 0, -1, "S", "SEVER" ), SEVEROZÁPAD ( -1, -1, "SZ", "SEVEROZAPAD" ), ZÁPAD ( -1, 0, "Z", "ZAPAD" ), JIHOZÁPAD ( -1, 1, "JZ", "JIHOZAPAD" ), JIH ( 0, 1, "J", "JIH" ), JIHOVÝCHOD ( 1, 1, "JV", "JIHOVYCHOD" ), ; //== KONSTANTNÍ ATRIBUTY TŘÍDY =============================================== public static final int SMĚRŮ = 8; private static final int MASKA = 7; private static final Map názvy = new HashMap ( SMĚRŮ*3 ); private static final int[][] posun = new int[SMĚRŮ][2]; private static final Směr8[] SMĚRY = values(); static { for( Směr8 s : SMĚRY ) { posun[s.ordinal()][0] = s.přepravka.dx; posun[s.ordinal()][1] = s.přepravka.dy; názvy.put( s.přepravka.zkratka, s ); názvy.put( s.přepravka.název, s ); názvy.put( s.přepravka.názevBHC,s ); s.přepravka = null; } //== DOČASNÉ ATRIBUTY INSTANCÍ =============================================== private static class Přepravka { int dx, dy; String zkratka, název, názevBHC; } Přepravka přepravka; //== KONSTRUKTORY A TOVÁRNÍ METODY =========================================== private Směr8( int dx, int dy, String zkratka, String názevBHC ) { přepravka = new Přepravka(); přepravka.dx = dx; přepravka.dy = dy; přepravka.zkratka = zkratka; přepravka.název = name(); přepravka.názevBHC = názevBHC; } Deklarace hodnot (veřejných konstant) daného typu Instance si svá data pamatují v polích, která jsou atributy třídy Statický inicializační blok inicializující pole a mapu hodnotami z přepravky Mapa pro získání instance zadaného názvu či zkratky Přepravka pro dočasné uchování hodnot zadaných konstruktoru, než je bude možno uložit do mapy a příslušných polí Konstruktor ukládá všechny parametry do přepravky, aby je bylo možno vyzvednout ve statickém inicializačním bloku

63 ICZ Copyright © 2009, Rudolf Pecinovský 63 Výběr rozšiřujících metod třídy Směr8 public Směr8 čelemVzad() { return SMĚRY[MASKA & (4+ordinal())]; } public int dx() { return posun[ordinal()][0]; } public int dalšíX( int x, int vzdálenost ) { return x + dx()*vzdálenost; } public Pozice dalšíPozice( Pozice pozice, int vzdálenost ) { return new Pozice( dalšíX( pozice.x, vzdálenost ), dalšíY( pozice.y, vzdálenost ) ); }

64 ICZ Copyright © 2009, Rudolf Pecinovský 64 Funkční výčtový typ ►Jednotlivé hodnoty výčtového typu mohou být instancemi jeho podtříd ►Každá hodnota pak bude na danou zprávu (volání metody) reagovat jinak ►Oblíbené použití: ● Každá instance představuje operaci, takže se v závislosti na výběru instance provede příslušná operace ►Příklady ● Výčtový typ operací ( např. PLUS, MINUS, KRAT, DELENO) ● Výčtový typ zdrojů (např. KLÁVESNICE, SOUBOR, SÍŤ) ● Třída Člověk v doprovodných programech ● Diamanty (obrázek) Diamanty

65 ICZ Copyright © 2009, Rudolf Pecinovský 65 Příklad funkčního výčtového typu ►Metody instancí musí překrývat metodu předka, protože jinak by nebyly zvenku vidět ►Metody mohou definovat i „funkční vlastnosti“ instancí – např. jak se daná instance-tvar nakreslí – viz DiamantyDiamanty public enum Operace { PLUS { public int proveď( int a, int b) { return a + b; } }, MINUS { public int proveď( int a, int b) { return a - b; } }; public abstract proveď( int a, int b ); } //... Operace op = PLUS; int výsledek = op.proveď( x, y ); //...

66 ICZ Copyright © 2009, Rudolf Pecinovský 66 Příklad 2: Člověk1/2 public enum ČlověkE50 { LENOCH { public void budíček() { System.out.println("Pomalu vstávám" ); } public void práce() { System.out.println("Líně pracuji" ); } public void volno() { System.out.println("Odcházím spát" ); } public void spánek() { System.out.println("Stále spím" ); } }, ČILOUŠ { public void budíček() { System.out.println("Rychle vstávám" ); } public void práce() { System.out.println("Čile pracuji" ); } public void volno() { System.out.println("Aktivně odpočívám" ); } public void spánek() { System.out.println("Omdlím a spím" ); } }, PRACANT { public void budíček() { System.out.println("Brzy vstávám" ); } public void práce() { System.out.println("Zaníceně pracuji" ); } public void volno() { System.out.println("Stále pracuji" ); } public void spánek() { System.out.println("Usínám nad prací" ); } }; abstract public void budíček(); abstract public void práce(); abstract public void volno(); abstract public void spánek();

67 ICZ Copyright © 2009, Rudolf Pecinovský 67 Příklad 2: Člověk2/2 /********************************************************** * Definice pracovního dne člověka. */ private static void den( ČlověkE50 č ) { System.out.println("Pracovní den instance " + č); č.budíček(); č.práce(); č.volno(); č.spánek(); } public static void test() { den( LENOCH ); den( ČILOUŠ ); den( PRACANT ); } public static void main( String[] args ) { test(); }

68 ICZ Copyright © 2009, Rudolf Pecinovský 68 Vrstvený výčtový typ ►Někdy potřebujeme, aby sada dostupných instancí závisela na jistých okolnostech ● Příklad: Směr360 – Směr8 – Směr4 ►Standardní výčtový typ v Javě nepodporuje dědičnost (je třeba se vrátit ke „klasice“) ● Nelze vytvořit explicitního potomka třídy Enum ● Není možné vytvořit potomka výčtového typu ►Potomek musí být speciálním případem předka ►Pozor na problémy s typy návratových hodnot

69 Vaše jistota na trhu IT Fond (Pool)024 ►Fond využijeme ve chvíli, kdy potřebujeme z nějakého důvodu omezit počet vytvořených instancí a místo vytváření instancí nových dáme přednost „reinkarnaci“ (znovuoživení) instancí dříve použitých a v danou chvíli již nepoužívaných. Obsah

70 ICZ Copyright © 2009, Rudolf Pecinovský 70 Charakteristika ►Používá se v situacích, kdy potřebujeme omezit počet existujících instancí nějaké třídy … ● Připojení k databázi ● Objekty náročné na různé zdroje ►… případně počet instancí vytvářených ● Objekty, jejichž vytvoření je drahé a důvodně předpokládáme, že je brzy bude chtít někdo využít ● Vlákna, animované objekty, … ►Vždy, když objekt potřebujeme, požádáme o něj fond, a po použití objekt zase do fondu vrátíme ►Umí-li si objekt sám zjistit, že jeho práce skončila, můžeme explicitní vracení objektu fondu vypustit ● Vlákna

71 ICZ Copyright © 2009, Rudolf Pecinovský 71 Možné přístupy ►Pevný počet instancí s frontou požadavků ● Je předem dán maximální počet instancí ● Objeví-li se víc požadavků, než je povolený počet instancí, nepokryté požadavky se řadí do fronty, kde čekají, až se některá z instancí uvolní ● Typické použití: databázová připojení ►Dynamické zvyšování počtu instancí ● Počet instancí se dynamicky zvyšuje podle potřeby ● Když přijde požadavek a všechny instance jsou „rozebrané“, vytvoří se nová ● Typické použití: instance, jejichž vytvoření je „drahé“ a vyplatí se je proto nerušit, ale místo toho znovu použít ● Příklad: vlákna, animované objekty

72 ICZ Copyright © 2009, Rudolf Pecinovský 72 Implementace – řešené problémy ►Vyhledávání volných instancí ● Je-li instancí ve fondu málo (typicky do 5), lze vyhledat prázdnou instancí projitím pole instancí ● Je-li jich víc, dvě možnosti: ●Ukládat přidělené do mapy, kde ji bude možno po uvolnění rychle vyhledat a přeřadit mezi volné ●Ukládat instance do zřetězeného seznamu (přidělená se přesune z počátku na konec, uvolněná se přesune naopak na počátek) ►Přidělování a vracení jednotlivých instancí ● Jak zabezpečit, aby objekt, který instanci vrátil, už nemohl danou instanci používat ●Např. když si instanci půjčenou z fondu předává několik metod a jedna metoda instanci vrátí dřív, než ji jiná přestane používat ● Jak zjistit, kdo instanci zapomněl vrátit

73 ICZ Copyright © 2009, Rudolf Pecinovský 73 Přidělování a vracení instancí ►Použití vrácené či cizí instance ● Instance dostane po přidělení jednoznačné ID, které bude parametrem všech jejích metod a jehož prostřednictvím se bude oprávněný „vlastník“ instance vždy identifikovat ● Po vrácení instance bude ID odebráno a nový vlastník dostane přidělen nové ID ►Zapomenuté uvolnění ● Při přidělení instance se může vytvořit a zapamatovat výjimka, která jednoznačně identifikuje místo přidělení i žadatele – tu si bude instance pamatovat a na požádání uložené informace prozradí ►Bezpečné řešení zdržuje, takže je v časově kritických případech lze modifikovat tak, že se bude kompletně spouštět pouze v režimu ladění

74 ICZ Copyright © 2009, Rudolf Pecinovský 74 Příklad ► IFond ► Fond ►Brownův pohyb molekul

75 ICZ Copyright © 2009, Rudolf Pecinovský 75 Příklad: Rozhraní IFond package rup.česky.vzory._12_fond; public interface IFond { /********************************************************** * Vrátí volnou instanci; není-li v rezervoáru žádná * volná instance, vytvoří novou. */ public T dejIhned(); /********************************************************** * Vrátí volnou instanci; není-li v rezervoáru žádná * volná instance, zařadí žadatele do fronty čekajících. */ public T dejPočkám(); /********************************************************** * Vrátí volnou instanci; není-li v rezervoáru žádná * volná instance, vrátí null; */ public T dejVolnou(); /********************************************************** * Předá do rezervoáru dále nepotřebnou instanci. */ public void vracímInstanci( T instance ); }

76 Vaše jistota na trhu IT Originál (Original)025 ►Návrhový vzor Originál použijeme v situaci, kdy budeme dopředu vědět, že se v aplikaci bude používat pouze malý počet různých instancí, avšak tyto instance budou požadovány na řadě míst kódu. Obsah

77 ICZ Copyright © 2009, Rudolf Pecinovský 77 Charakteristika ►Hodnotový neměnný typ, který zabezpečuje, že od každé hodnoty bude existovat jen jedna instance ►Počet hodnot není předem omezen, vychází však často ze společné výchozí sady ►Nevýhody ● Při žádosti o instanci je třeba zjistit, zda již neexistuje ►Výhody ● Zbytečně se nám nekumulují duplicitní instance ● Není třeba používat equals ►Příklad: Barva v knihovně Tvary

78 ICZ Copyright © 2009, Rudolf Pecinovský 78 Implementace ►Tovární metody specifikují parametry potřebné k určení požadované hodnoty ►Alternativně je možno přiřadit instanci název a instance pak vybírat z mapy jako u výčtových typů ►Pro zrychlení vyhledávání se přehled o existujících instancích se udržuje ve formě mapy příp. ►Má smysl, pokud instance málo vytváříme, ale často používáme – šetříme tak čas správce paměti ►Příklad: rup.česky.tvary.Barva

79 Vaše jistota na trhu IT Muší váha (Flyweight)026 ►Vzor označovaný jako Muší váha používáme ve chvíli, kdy řešení problému vyžaduje vytvoření značného množství objektů. Ukazuje, jak je možné toto množství snížit tím, že místo skupiny objektů s podobnými charakteristikami použijeme jeden sdílený objekt tak, že z něj vyjmeme část jeho stavu, která odlišuje jednotlivé zastupované objekty, a volané metody se tyto informace v případě potřeby dozvědí z vnějšího zdroje prostřednictvím svých parametrů. Obsah

80 ICZ Copyright © 2009, Rudolf Pecinovský 80 Charakteristika ►Řeší situace, které při standardním přístupu vyžadují vytvoření příliš velkého množství objektů ►Vzor řeší problém tak, že jeden objekt slouží jako zástupce několika „virtuálních“ objektů ►Příklady ● V textovém editoru není představován každý znak v dokumentu samostatným objektem, ale všechny stejné znaky zastupuje představitel daného znaku ● V situacích, kde vystupuje malá množina různých objektů v řadě různých navzájem si velmi podobných mutacích (viz hra rup.česky.vzory._13_muší_váha.diamanty.Diamanty )

81 ICZ Copyright © 2009, Rudolf Pecinovský 81 Implementace ►Stav objektu je rozdělen do dvou částí ● Vnitřní stav, který nese klíčové informace o objektu a který je společný všem „virtuálním“ objektům zastupovaným daným objektem ● Vnější stav, v němž se jednotlivé zastupované objekty liší, a který je proto předáván metodám v parametrech ►Příklady ● Textový editor: ●Vnitřním stavem objektu je zastupovaný znak a konkrétní formát, ●Vnějším stavem je pozice znaku v dokumentu ● Diamanty (pgm) Diamanty ●Vnitřním stavem je vzhled obrazce, ●Vnějším stavem je jeho umístění na hrací desce

82 ICZ Copyright © 2009, Rudolf Pecinovský 82 Příklad: Hra Diamanty ► rup.česky.vzory._13_muší_váha.diamanty.Diamanty ►Všechna místa na hrací desce, na nichž se nachází diamant daného tvaru, se odkazují na stejný objekt ►Diamant zná svůj tvar, ale od programu se dozví, na kterém místě se právě nachází

83 Vaše jistota na trhu IT 03 Skrývání implementace03 ►Zástupce (Proxy)031Zástupce (Proxy) ►Příkaz (Command)032Příkaz (Command) ►Iterátor (Iterator)033Iterátor (Iterator) ►Stav (State)034Stav (State) ►Šablonová metoda (Template Method)035Šablonová metoda (Template Method) Obsah

84 Vaše jistota na trhu IT Zástupce (Proxy)031 ►Zavádí zástupný objekt, který odstiňuje zastupovaný objekt od jeho uživatelů a sám řídí přístup uživatelů k zastupovanému objektu. Obsah

85 ICZ Copyright © 2009, Rudolf Pecinovský 85 Druhy zástupců1/2 ►Vzdálený zástupce (remote proxy) ● Lokální zástupce vzdáleného objektu (zastupuje objekt v jiném adresovém prostoru, na jiném VM, na jiném počítači, …) ● Java RMI, CORBA, XML/SOAP, … ►Virtuální zástupce (virtual proxy) ● Potřebujeme-li odložit okamžik skutečného vytvoření objektu (vytvoření objektu je drahé – load on demand) ● Rozlišuje mezi vyžádáním objektu a jeho skutečným použitím ● Transparentní optimalizace (např. cache) ►Chytrý odkaz (smart reference) ● Doplňuje komunikaci s objektem o doprovodné operace (počítání odkazů, správa paměti, logování, …) ● Příklad: debugger mající za úkol zastavit při n-tém přístupu k objektu

86 ICZ Copyright © 2009, Rudolf Pecinovský 86 Druhy zástupců2/2 ►Ochranný zástupce (protection proxy) ● Potřebujeme-li skrýt pravou identitu objektu ● Je-li třeba ověřovat přístupová práva volajících objektů ● Je-li třeba rozšířeně validovat parametry ►Modifikační zástupce (Copy-on-write proxy) ● Opožděné kopírování objektů až při jejich modifikaci ►Synchronizační zástupce (Synchronization proxy) ● Transparentní synchronizace vláken při přístupu k objektu

87 ICZ Copyright © 2009, Rudolf Pecinovský 87 Implementace ►Zástupce obaluje zastupovaný objekt a zprostředkovává komunikaci okolního programu se zastupovaným objektem ►V převážné většině případů je odkaz na zastupovaný objekt atributem zástupce, kterému jsou po případné kontrole předány požadavky a naopak obdržené výsledky jsou předány žadateli ►V případě ochranného zástupce lze při mírnějších požadavcích na ochranu (nehrozí-li záměrný útok) „skrýt“ zastupovaný objekt za pouhé rozhraní

88 ICZ Copyright © 2009, Rudolf Pecinovský 88 Diagram tříd zástupců

89 ICZ Copyright © 2009, Rudolf Pecinovský 89 Vzdálený zástupce (Remote proxy) ►Zastupuje objekt umístěný jinde (často na jiném VM) ►Zprostředkovává komunikaci mezi zastupovaným vzdáleným objektem a objekty z okolí zástupce ►Úkol: zapouzdřit a skrýt detaily komunikace ● Klienti komunikují se zastupovaným objektem jako by byl místní ● Klient nemusí vůbec poznat, v kterém okamžiku je zastupován místní objekt a ve které je zastupován skutečně vzdálený objekt ►Musí být stále připraven na možnost selhání komunikace a být schopen vyhodit výjimku

90 ICZ Copyright © 2009, Rudolf Pecinovský 90 Vzdálený zástupce – schéma

91 ICZ Copyright © 2009, Rudolf Pecinovský 91 Ochranný zástupce (protection proxy) ►Umožňuje zatajit skutečný typ zastupovaného objektu ►Definuje pouze ty metody, které má objekt umět ►Může doplnit kontrolu přístupových práv ►Možné implementace ● Skrýt skutečnou třídu za rozhraní – použitelné, pokud chceme pouze zjednodušit (tj. zpřehlednit) rozhraní ● Vytvořit skutečného zástupce, tj. objekt, který obsahuje odkaz na zastupovaný objekt, jemuž předává zprávy a od nějž přebírá odpovědi – potřebujeme-li ochránit před možným útokem

92 ICZ Copyright © 2009, Rudolf Pecinovský 92 Ukázka kódu ochranného zástupce public class Zástupce { private Zastupovaný z; Zástupce( Zastupovaný zz ) { z = zz } Zástupce( Object... parametry ) { z = new Zastupovaný( parametry ); } public int metoda( Object... parametry ) { return z.metoda( parametry ); }

93 ICZ Copyright © 2009, Rudolf Pecinovský 93 Příklad: Rozhraní IZastávka package rup.česky.vzory._14_zástupce.doprava; public interface IZastávka extends IKreslený { /************************************************* * Vrátí linku, na které zastávka leží. */ public Linka getLinka(); /************************************************* * Vrátí pozici zastávky, tj. jejího středu. */ public Pozice getPozice(); /************************************************* * Vrátí odkaz na předchozí zastávku na trati. */ public IZastávka getPředchozí(); /************************************************* * Vrátí odkaz na následující zastávku na trati.*/ public IZastávka getNásledující(); }

94 ICZ Copyright © 2009, Rudolf Pecinovský 94 Příklad: Třída Zastávka private class Zastávka implements IZastávka { //== KONSTRUKTORY A TOVÁRNÍ METODY ============================ public Zastávka( Linka linka, int x, int y ); public Zastávka( Zastávka předchozí, int x, int y ); private Zastávka(Zastávka předchozí,Linka linka,int x,int y); //== VEŘEJNÉ METODY INSTANCÍ ================================== public Linka getLinka(); public Pozice getPozice(); public IZastávka getPředchozí(); public IZastávka getNásledující(); public void nakresli(Kreslítko g); public String toString(); public IZastávka napoj( int x, int y ); public void napojNa( Zastávka předchozí ); public Zastávka zruš(); }

95 ICZ Copyright © 2009, Rudolf Pecinovský 95 Příklad: java.util.Collections ► public static Xyz checkedXyz(Xyz c, Class type) ► public static Xyz unmodifiableXyz(Xyz c) ►Za Xyz lze dosadit: ● Collection ● Set ● List ● Map ● SortedSet ● SortedMap

96 ICZ Copyright © 2009, Rudolf Pecinovský 96 Virtuální zástupce (virtual proxy) ►Použijeme jej, když je vytváření objektu drahé a objekt ve skutečnosti není potřeba od začátku celý ►Zástupe vytvoří zastupovaný objekt (např. načte obrázek), až když je doopravdy potřeba ►Do okamžiku skutečného vytvoření může ● Nahrazovat volání metod zastupovaného objektu voláním vlastních náhradních metod (např. dotaz na požadovaný paměťový prostor pro budoucí obrázek) ● Připravit a uchovávat seznam konfiguračních parametrů, které se použijí v okamžiku skutečného vytvoření objektu

97 ICZ Copyright © 2009, Rudolf Pecinovský 97 Chytrý odkaz (smart reference) ►Umožňuje doplnit komunikaci s objektem o další akce ● Kontrola přístupových práv k objektu ● Evidence požadavků na služby objektu ● Zamčení objektu při zápisu ►Umožňuje zefektivnit práci s objektem ● Při první žádosti o objekt se objekt nevytváří, ale zavádí se do paměti dříve vytvořený objekt uložený v nějaké vnější paměti ● Udržuje spojení s databází ještě chvíli po poslední žádosti ►Virtuální zástupce je druh chytrého odkazu ● Musí se umět rozhodnout, na co stačí sám, kdy už je třeba zastupovaný objekt skutečně vytvořit

98 ICZ Copyright © 2009, Rudolf Pecinovský 98 Synchronizační zástupce ►Příklad: synchronizované kolekce ve třídě java.util.Collections získané voláním metod public static Xyz synchronizedXyz(Xyz c) ►Za Xyz lze dosadit: ● Collection ● Set ● List ● Map ● SortedSet ● SortedMap

99 Vaše jistota na trhu IT Příkaz (Command)032 ►Zabalí metodu do objektu, takže s ní pak lze pracovat jako s běžným objektem. To umožňuje dynamickou výměnu používaných metod za běhu programu a optimalizaci přizpůsobení programu požadavkům uživatele. Obsah

100 ICZ Copyright © 2009, Rudolf Pecinovský 100 Motivace ►Občas víme, že se v nějaké situaci má něco provést, ale při psaní programu nemáme ani vzdálenou představu o tom, co to bude ● Víme, že při stisku tlačítka má program nějak zareagovat, ale až při vložení konkrétního tlačítka do konkrétního GUI budeme tušit, jaká je ta správná reakce. Při definici objektu Tlačítko o tom však nemáme ani vzdálené tušení ►Chceme oddělit objekt, který spouští nějakou akci, od objektu, který ví, jak ji vykonat ►Potřebovali bychom, aby se s akcemi mohlo pracovat stejně jako s daty 1. Připravíme „proměnnou“ 2. Až budeme vědě, co se má dělat, vložíme do proměnné kód 3. Až budeme potřebovat kód provést, vytáhneme jej z proměnné a provedeme

101 ICZ Copyright © 2009, Rudolf Pecinovský 101 Implementace ►Vzor doporučuje zabalit akci (skupinu akcí) do objektu a tím převést akci na data ►Definujeme rozhraní specifikující charakteristiku (signaturu) požadovaných metod ►Vytvoříme objekty implementující toto rozhraní a realizující jednotlivé typy akcí ● Příslušné třídy mívají jedinou instanci, i když často nebývají definovány jako jedináčci ►Podle toho, jakou akci je třeba realizovat, naplní se vyhrazená proměnná odkazem na příslušný akční objekt

102 ICZ Copyright © 2009, Rudolf Pecinovský 102 Příkaz × Služebník ►Služebník: Mám obsluhované objekty a hledám někoho, kdo by je „obsloužil“, tj. kdo by s nimi (nad nimi) provedl požadovanou operaci ►Příkaz: Mám připravený, resp. připravuji příkaz (akci, obsluhu) který vyžaduje provedení nějaké akce, resp. nějakých akcí. Definuji rozhraní ( interface ) s požadavky na objekt, který by vykonání požadované akce zabezpečil

103 ICZ Copyright © 2009, Rudolf Pecinovský 103 Vyhledání položky1/2 ►K vyhledání prvku v setříděném polí slouží metody Arrays.binarySearch(T[] ta, T klíč) Arrays.binarySearch(T[] ta, T klíč, Comparator c) kde typ T může být libovolný primitivní či objektový typ ►K vyhledání prvku v setříděném seznamu slouží metody Collections.binarySearch(List lt, T klíč) Collections.binarySearch(List ta, T klíč, Comparator c) ►K získání komparátoru, který třídí v obráceném pořadí, slouží Collections.reverseOrder() Collections.reverseOrder(Comparator cmp)

104 ICZ Copyright © 2009, Rudolf Pecinovský 104 Třídění a vyhledání maxima/minima ►K setřídění kolekce slouží metody List.sort(List coll) List.sort(List coll, Comparator c) ►Obdobně je možné třídit pole voláním metod z třídy java.util.Arrays ►K vyhledání největšího prvku v kolekci slouží metody Collections.max(Collection coll) Collections.max(Collection coll, Comparator c) ►K vyhledání nejmenšího prvku v kolekci slouží metody Collections.min(Collection coll) Collections.min(Collection coll, Comparator c)

105 ICZ Copyright © 2009, Rudolf Pecinovský 105 Zdrojový kód metody max(Collection ) //Deklarace typových parametrů jsou zjednodušené public static > T max(Collection coll) { Iterator i = coll.iterator(); T candidate = i.next(); while(i.hasNext()) { T next = i.next(); if (next.compareTo(candidate) > 0) candidate = next; } return candidate; } ►Příklad převzat z knihovní třídy java.util.Collections Kolekcí budeme procházet pomocí iterátoru Připravíme si kandidáta na maximum Procházíme zbytkem kolekce, a je-li někdo větší než kandidát, prohlásíme jej za lepšího kandidáta

106 ICZ Copyright © 2009, Rudolf Pecinovský 106 Zdrojový kód verze s komparátorem //Deklarace typových parametrů jsou zjednodušené public static T max(Collection coll, Comparator comp) { if (comp==null) return (T)max((Collection ) (Collection) coll); Iterator i = coll.iterator(); T candidate = i.next(); while(i.hasNext()) { T next = i.next(); if (comp.compare(next, candidate) > 0) candidate = next; } return candidate; } private interface SelfComparable extends Comparable {} Je-li zadán prázdný odkaz na komparátor, zkusíme verzi bez komparátoru Je-li dodán komparátor, připraví si iterátor a kandidáta na maximum Verze bez komparátoru vyžaduje nativně porovnatelné objekty – definuje si soukromé vnořené rozhraní, na něž se pokusí instance přetypovat Pak pokračuje stejně jako minule, jenom s jinou metodou porovnání hodnot

107 ICZ Copyright © 2009, Rudolf Pecinovský 107 Příklad: Třídění nativní a modulo public class Modulo2 implements Comparable { private final int hodnota; private final int modul; public Modulo2( int h ) { hodnota = h; modul = h % 10; }//============================================================= public String toString() { return String.format( "%2s", hodnota); }//============================================================= private static void tiskni( String s, Modulo2[] mm) { System.out.println( s + Arrays.asList( mm ) ); }//============================================================= public static final void test() { Random rnd = new Random(); Modulo2[] mm = new Modulo2[20]; for( int i=0; i < mm.length; mm[i++] = new Modulo2(rnd.nextInt(100)) ); tiskni( "Výchozí: ", mm ); Arrays.sort( mm ); tiskni( "Setříděné: ", mm ); Arrays.sort( mm, new Comp() ); tiskni( "Comparator:", mm ); }//============================================================= public int compareTo(Modulo2 m) { return (hodnota - m.hodnota); }//============================================================= private static class Comp implements Comparator { public int compare( Modulo2 a, Modulo2 b) { if( a.modul != b.modul ) return (a.modul - b.modul); else return a.hodnota - b.hodnota; } Objekt má dva atributy: hodnotu a modul Vyrobím pole objektů Setřídím je dvěma způsoby

108 ICZ Copyright © 2009, Rudolf Pecinovský 108 Příklad: Třídění nativní a modulo public class Modulo2 implements Comparable { private final int hodnota; private final int modul; public Modulo2( int h ) { hodnota = h; modul = h % 10; }//============================================================= public String toString() { return String.format( "%2s", hodnota); }//============================================================= private static void tiskni( String s, Modulo2[] mm) { System.out.println( s + Arrays.asList( mm ) ); }//============================================================= public static final void test() { Random rnd = new Random(); Modulo2[] mm = new Modulo2[20]; for( int i=0; i < mm.length; mm[i++] = new Modulo2(rnd.nextInt(100)) ); tiskni( "Výchozí: ", mm ); Arrays.sort( mm ); tiskni( "Setříděné: ", mm ); Arrays.sort( mm, new Comp() ); tiskni( "Comparator:", mm ); }//============================================================= public int compareTo(Modulo2 m) { return (hodnota - m.hodnota); }//============================================================= private static class Comp implements Comparator { public int compare( Modulo2 a, Modulo2 b) { if( a.modul != b.modul ) return (a.modul - b.modul); else return a.hodnota - b.hodnota; } Výchozí: [99, 79, 18, 81, 47, 88, 88, 42, 56, 85, 61, 23, 41, 44, 3, 46, 74, 52, 17, 23] Setříděné: [ 3, 17, 18, 23, 23, 41, 42, 44, 46, 47, 52, 56, 61, 74, 79, 81, 85, 88, 88, 99] Comparator:[41, 61, 81, 42, 52, 3, 23, 23, 44, 74, 85, 46, 56, 17, 47, 18, 88, 88, 79, 99]

109 ICZ Copyright © 2009, Rudolf Pecinovský 109 Příklad na vektor příkazů: Třída Kostka /** Generátor vzhledu vrchni strany kostky * při hození jednotlivých čísel. */ private static final IHod[] hod = { null, new IHod() { public void zobraz() { /* 1 */ }, new IHod() { public void zobraz() { /* 2 */ }, new IHod() { public void zobraz() { /* 3 */ }, new IHod() { public void zobraz() { /* 4 */ }, new IHod() { public void zobraz() { /* 5 */ }, new IHod() { public void zobraz() { /* 6 */ }, }; /********************************************** * Simuluje hod čísla, které následně zobrazí * číslem a vypodobněním horní strany kostky. */ public void hoď() { int číslo = RND.nextInt( 6 ) + 1; System.out.println( "Padlo číslo: " + číslo ); hod[ číslo ].zobraz(); }

110 Vaše jistota na trhu IT Iterátor (Iterator)033 ►Zprostředkuje jednoduchý a přehledný způsob sekvenčního přístupu k objektům uloženým v nějaké složité struktuře (většinou v kontejneru), přičemž implementace této struktury zůstane klientovi skryta. Obsah

111 ICZ Copyright © 2009, Rudolf Pecinovský 111 Motivace ►Instance, které ukládáme do kontejneru, neodkládáme jako do popelnice – budeme je chtít v budoucnu použít ►Kontejner nás však nemůže nechat se ve svých útrobách přehrabovat – to by nám musel prozradit svou implementaci ►Potřebujeme mít možnost se kdykoliv dostat k uloženým datům, aniž by kontejner byl nucen cokoliv prozradit o své implementaci ►Problém řeší aplikace návrhového vzoru Iterátor

112 ICZ Copyright © 2009, Rudolf Pecinovský 112 Charakteristika ►Skryje způsob uložení objektů v kontejneru a přitom umožní procházet kontejnerem a prácovat s uloženými prvky ►Sekvenční (externí) iterátor ● Na požádání předává externímu žadateli jednotlivé uložené objekty ● Vlastní akci iniciuje a zabezpečuje klient ►Dávkový (interní) iterátor ● Převezme od klienta filtr specifikující ošetřované prvky a příkaz, který se má na každý ošetřovaný prvek aplikovat ● Sám prochází prvky a na ty, které projdou filtrem, aplikuje obdržený příkaz

113 ICZ Copyright © 2009, Rudolf Pecinovský 113 Princip externího iterátoru ►Kontejner definuje speciální třídu – iterátor, jejíž instance ví, jak jsou svěřená data uložena ►Tomu, kdo chce pracovat s uloženými daty vrátí kontejner na požádání instanci iterátoru, jenž mu přístup k uloženým datům zprostředkuje ►Instance iterátoru na požádání vrátí odkaz na další z instancí uložených v kontejneru ►Až iterátor všechna data vyčerpá, oznámí, že už další nejsou ►Tazatel se tak dostane ke všem uloženým datům, aniž by se dozvěděl, jak jsou vlastně uložena

114 ICZ Copyright © 2009, Rudolf Pecinovský 114 Implementace ►Iterátor bývá v Javě implementován jako vnitřní třída ►Rozhraní Iterator ze standardní knihovny vyžaduje implementaci metod: ● boolean hasNext() ● E next() ● void remove() (implementace může být formální) ►Seznamy umí vrátit také ListIterator, který přidává ● Možnost vložení nového prvku před či za aktuální ● Změnu směru průchodu seznamem ● Nahrazení naposledy vráceného prvku jiným ● Vrácení indexu předchozího, resp. následujícího prvku

115 ICZ Copyright © 2009, Rudolf Pecinovský 115 interface Iterator package java.util; public interface Iterator { /** Je ještě nějaká instance k dispozici? */ boolean hasNext(); /** Vrátí odkaz na další instanci. */ E next(); /** Odebere z kolekce * naposledy vrácenou instanci. * Metoda nemusí být plně implementována. */ void remove(); }

116 ICZ Copyright © 2009, Rudolf Pecinovský 116 Ukázka použití: tisk kolekce s titulkem public static void println( String název, Collection kolekce ) { System.out.print( název + ": (" ); String oddělovač = ""; for( Iterator it = kolekce.iterator(); it.hasNext(); /* nic */ ) { Object o = it.next(); String s = o.toString(); System.out.print( oddělovač + s ); oddělovač = ", "; } System.out.println( ")" ); }

117 ICZ Copyright © 2009, Rudolf Pecinovský 117 Starší implementace ►Java původně (tj. před verzí 1.2) definovala iterátor jako interface java.util.Enumeration s metodami ● boolean hasMoreElements() ● Object nextElement() ►V Java ME zůstává tato definice jako jediná

118 ICZ Copyright © 2009, Rudolf Pecinovský 118 Iterovatelné objekty ►Java 5 zavedla iterovatelné objekty – jejich třídy implementují rozhraní Iterable ►Rozhraní požaduje implementaci jediné metody: public Iterator iterator() ►Jako iterovatelný objekt je možno definovat i … ● měřící zařízení, které vrací nekonečný sled měření ● generátor objektů (např. náhodných či testovacích) ● vstupní soubor ● … ►Zařazením objektu mezi iterovatelné získáme možnost využít knihovních metod, které s pracují s iterovatelnými objekty + „dvojtečkové“ verze cyklu for

119 ICZ Copyright © 2009, Rudolf Pecinovský 119 Tisk kolekce s novou verzí cyklu public static void println( String název, Collection kolekce ) { System.out.print( název + ": (" ); String oddělovač = ""; for( Object o : kolekce ) { //Objekt již mám přiřazen String s = o.toString(); System.out.print( oddělovač + s ); oddělovač = ", "; } System.out.println( ")" ); }

120 ICZ Copyright © 2009, Rudolf Pecinovský 120 Příklad: Fronta – atributy a metody public class Fronta implements Iterable { private final List prvky = new LinkedList (); public void zařaď( E e ) { prvky.add( e ); } public E další() { if( prvky.size() == 0 ) return null; E ret = prvky.get(0); prvky.remove(0); return ret; } public Iterator iterator() { return new MůjIterator( this ); }

121 ICZ Copyright © 2009, Rudolf Pecinovský 121 Příklad: Fronta – vnořená třída private class MůjIterator implements Iterator { private int pořadí = 0; private Fronta f; MůjIterator( Fronta fronta ) { f = fronta; } public boolean hasNext() { return (pořadí < f.prvky.size()); } public E next() { return f.prvky.get( pořadí++ ); } public void remove() { throw new UnsupporteOperationException(); } Neplnohodnotná implementace – volání metody způsobí chybu Protože je definována uvnitř třídy, má přístup k soukromým složkám jejích instancí

122 ICZ Copyright © 2009, Rudolf Pecinovský 122 Příklad: Fronta – Test public static void test() { Random rnd = new Random(); Fronta fronta = new Fronta (); System.out.println("===== Začátek testu ====="); System.out.println("Přidáváme:"); for( int i=0; i < 5; i++ ) { Integer číslo = new Integer(rnd.nextInt(100)); fronta.zařaď( číslo ); System.out.print("Přidáno: " + číslo); System.out.print (" Stav:"); //Použití cyklu for(:) na instance třídy Fronta for( Integer fi : fronta ) System.out.print( " " + fi ); System.out.println(""); } System.out.println("\nOdstraňujeme:"); for(;;) { Integer další = fronta.další(); if( další == null ) break; // > System.out.print("Obslouženo: " + další); System.out.print (" Stav:"); //Použití cyklu for(:) na instance třídy Fronta for( Integer fi : fronta ) System.out.print( " " + fi ); System.out.println(""); } System.out.println("===== Fronta obsloužena ====="); }

123 ICZ Copyright © 2009, Rudolf Pecinovský 123 Příklad: iterátor složkou public interface IPříkaz { public void příkaz( Object... objects ); } public class Složka implements Iterable { public Složka( String složka ) {/*tělo*/} public Složka( File složka ) {/*tělo*/} public void aplikuj( IPříkaz příkaz ) {/*tělo*/} public void setFilter( FileFilter filtr ) { this.filtr = filtr; } public void setComparator( Comparator comparator ) {/*tělo*/} public String toString() {/*tělo*/} public Iterator iterator() {return new FileIterator(filtr,comp);} private class FileIterator implements Iterator { public FileIterator(FileFilter filtr, Comparator komp) {/*tělo*/} public boolean hasNext() {/*tělo*/} public File next() {/*tělo*/} private File dalšíSoubor() {/*tělo*/} } Dávkový iterátor Návrhový vzor Příkaz Iterátor

124 ICZ Copyright © 2009, Rudolf Pecinovský 124 Rozhodnutí při definici iterátoru ►Kdo řídí iteraci: klient × kontejner (externí × interní) ● Externí iterátor je tvárnější (lze např. porovnat 2 kolekce), interní iterátor umožňuje zabezpečit větší robustnost ►Míru robustnosti iterátoru ● Jak citlivý bude na změnu struktury kontejneru v průběhu iterace ►Jakou množinu operací bude poskytovat ● Viz Enumeration × Iterator × ListIterator

125 Vaše jistota na trhu IT Stav (State)034 ►Řeší výrazný rozdíl mezi chováním objektu v různých stavech zavedením vnitřního stavu jako objektu reprezentovaného instancí některé ze stavových tříd. Změnu stavu objektu pak řeší záměnou objektu reprezentujícího stav. Obsah

126 ICZ Copyright © 2009, Rudolf Pecinovský 126 Motivace ►Chování objektu se výrazně liší v závislosti na stavu, v němž se právě nachází ►Při klasickém přístupu bylo třeba v každé stavově závislé metodě definovat rozhodovací sekvenci s popisy příslušné reakci v každé větvi ►Nevýhody: ● Kód je dlouhý a nepřehledný ● Zavádění nových stavů je obtížné ● Při modifikaci reakce v konkrétním stavu je třeba najít příslušné pasáže v záplavě okolního kódu

127 ICZ Copyright © 2009, Rudolf Pecinovský 127 Implementace ►Definice objektu se rozdělí na dvě části: ● Stavově nezávislou obsahující metody nezávisející na stavu ● Stavově závislou s metodami obsahujícími rozhodovací sekvence definující reakce se v závislosti na stavu ►Definuje se rozhraní (interface nebo abstraktní třída) deklarující metody s reakcemi závisejícími na stavu ►Pro každý stav se zavede samostatná třída implementující dané jednostavové rozhraní a definující chování objektu nacházejícího se v daném stavu ►Multistavový objekt definuje atribut odkazující na jednostavový objekt, na nějž pak deleguje reakce na zprávy závisející na aktuálním stavu

128 ICZ Copyright © 2009, Rudolf Pecinovský 128 Příklad: rup.česky.vzory._17_stav.autoa ►Použití abstraktní rodičovské třídy umožňuje: ● „Vytknout“ společné atributy ● Definovat na jednom místě metody pro přechody mezi stavy ● Definovat tovární metodu vracející instanci požadovaného stavu

129 Vaše jistota na trhu IT Šablonová metoda (Template Method)035 ►Definuje metodu obsahující kostru nějakého algoritmu. Ne všechny kroky tohoto algoritmu jsou však v době vzniku šablony známy – jejich konkrétní náplň definují až potomci třídy se šablonovou metodou prostřednictvím překrytí metod, které šablonová metoda volá. Obsah

130 ICZ Copyright © 2009, Rudolf Pecinovský 130 Charakteristika ►Návrhový vzor používaný i v učebnicích a kurzech, které se o návrhových vzorech vůbec nezmiňují ►Umožňuje podtřídám měnit části algoritmu bez změny samotného algoritmu ►Používá se při řešení typických úloh, jejichž přesné parametry budou známy až za běhu ►Umožňuje definovat metody, jejichž chování je definováno jen částečně; tyto části chování definují až potomci ►Jeden ze způsobů odstranění duplicit v kódu ►Takto bývají definovány klíčové objekty knihoven a rámců ● Aplety ● MIDlety

131 ICZ Copyright © 2009, Rudolf Pecinovský 131 Implementace ►Definuje metodu obsahující kostru nějakého algoritmu, u nějž však v době konstrukce ještě nejsou všechny jeho kroky známy ►Konkrétní náplň neznámých kroků definují až potomci na základě svých speciálních dodatečných znalostí ►Třída se šablonovou metodou definuje příslušnou kostru a pro dosud neznámé postupy definuje virtuální metody, které potomci překryjí svými vlastními ● Je-li jedno zmožných řešení např. „nedělat nic“, je možno definovat virtuální metodu jako prázdnou ● Neexistuje-li žádné přijatelné implicitní řešení, definuje se metoda jako abstraktní ►Při aplikaci vzoru bývá často použit také návrhový vzor Příkaz

132 ICZ Copyright © 2009, Rudolf Pecinovský 132 Template method – Velká a malá ryba ►Scénář: „Velké“ a „Malé“ ryby plavou oceánem ● ryby se pohybují náhodně ● velká ryba může plavat tam kde je malá (a sníst ji) ● malá ryba nemůže plavat tam kde je velká public void move() { vyber náhodný směr; najdi místo vtom směru; //odlišné pro druh ryby ověř lze-li tam plout; jestli ano, pluj; }

133 ICZ Copyright © 2009, Rudolf Pecinovský 133 Příklad: Aplety public class Applet extends Panel { public Applet() throws HeadlessException { public final void setStub(AppletStub stub) { public boolean isActive() { public URL getDocumentBase() { public URL getCodeBase() { public String getParameter(String name) { public AppletContext getAppletContext() { public void resize(int width, int height) { public void resize(Dimension d) { public void showStatus(String msg) { public Image getImage(URL url) { public Image getImage(URL url, String name) { public final static AudioClip newAudioClip(URL url) { public AudioClip getAudioClip(URL url) { public AudioClip getAudioClip(URL url, String name) { public String getAppletInfo() { public Locale getLocale() { public String[][] getParameterInfo() { public void play(URL url) { public void play(URL url, String name) { public void init() { public void start() { public void stop() { public void destroy() { }

134 ICZ Copyright © 2009, Rudolf Pecinovský 134 Příklad: MIDlety Start Ukončený Aktivní Čekající startApp pauseApp destroyApp startAppkonstruktor

135 ICZ Copyright © 2009, Rudolf Pecinovský 135 import javax.microedition.midlet.*; public class DieMIDlet_1 extends MIDlet { private static int m = 0; public DieMIDlet_1() { System.out.println("Midlet_1 Nr. "+ ++m +" constructed"); }// DieMIDlet_1() public void startApp() { System.out.println("Midlet_1 Nr. " + m + " activated"); new DieCast_1(this); //DieCast starts another thread }//startApp() public void pauseApp() {} public void destroyApp( boolean unconditional ) throws MIDletStateChangeException { System.out.println("Midlet_1 Nr. " + m + " destroyed"); notifyDestroyed(); }//public void destroyApp( boolean unconditional ) }//class DieMIDlet_1 extends MIDlet Příklad: DieMIDlet_1 – realizace

136 Vaše jistota na trhu IT 04 Optimalizace rozhraní04 ►Fasáda (Facade)041Fasáda (Facade) ►Adaptér (Adapter)042Adaptér (Adapter) ►Strom (Composite)043Strom (Composite) Obsah

137 Vaše jistota na trhu IT Fasáda (Facade)041 ►Ukazuje jak nahradit sadu rozhraní jednotlivých subsystémů sjednoceným rozhraním zastupujícím celý systém. Definuje tak rozhraní vyšší úrovně, které usnadní využívání podsystémů. Jejím cílem je zjednodušit rozhraní celého systému a snížit počet tříd, s nimiž musí uživatel přímo či nepřímo komunikovat. Obsah

138 ICZ Copyright © 2009, Rudolf Pecinovský 138 Charakteristika ►Použijeme jej ve chvíli, kdy nějaký systém začíná být pro své uživatele příliš složitý vzhledem k oblasti úloh, které chtějí s jeho pomocí řešit ►Z celého spektra dostupných metod vybere podmnožinu nejpoužívanějších, nebo přímo definuje vzorové verze metod pro nejčastěji používané úlohy ►Možné způsoby implementace ● Rozhraní či abstraktní třídy (příp. systém R+AT) jejichž implementaci definují až potomci ● Konfigurovatelná třída (slabší varianta předchozího) ● Samostatná třída (skupina tříd) poskytující nejčastěji požadované metody

139 ICZ Copyright © 2009, Rudolf Pecinovský 139 Komunikace tříd před a po použití fasády ►Příklad: ● javax.swing.JOptionPane

140 ICZ Copyright © 2009, Rudolf Pecinovský 140 Výhody použití ►Redukuje počet objektů, s nimiž klienti komunikují ● Snadnější použití subsystému ►Zmenšuje počet závislostí mezi klienty a subsystémem ● Odstraňuje některé komplexní a kruhové závislosti ● Méně závislostí při překladu i při běhu ►Liberální fasáda: neskrývá třídy subsystému ● Klient si může vybrat jednoduchost nebo použití na míru ►Přísná fasáda: nezaručuje implementaci systému ● Náhražka neexistující možnosti přísnějšího skrytí implementace ● Java 7 má zavést superpackages – pak nebude potřeba

141 Vaše jistota na trhu IT Adaptér (Adapter)042 ►Návrhový vzor Adaptér využijeme ve chvíli, kdy bychom potřebovali, aby třída měla jiné rozhraní, než to, které právě má. Pak mezi ní a potenciálního uživatele vložíme třídu adaptéru, která bude mít požadované rozhraní a konvertuje tak rozhraní naší třídy na rozhraní požadované. Obsah

142 ICZ Copyright © 2009, Rudolf Pecinovský 142 Motivace ►Občas potřebujeme, aby třída měla jiné rozhraní než to, které má ● Třída neimplementuje požadované rozhraní, nicméně poskytuje požadovanou funkčnost ● Příklad: používáme třídu z jedné knihovny, jejíž instance bychom mohli použít jako parametry metod jiné knihovny, ale tato jiná knihovna vyžaduje parametry implementující nějaké specifické rozhraní, které naše třída nezná ►Dopředu víme, že z hlediska požadované funkčnosti stačí implementovat pouze část daného rozhraní nicméně překladač vyžaduje kompletní implementaci ● Iterátor neumožňující odstraňovat prvky z kontejneru ● Kontejnery s předem zadaným, nezměnitelným obsahem ● Posluchači některých událostí při tvorbě GUI

143 ICZ Copyright © 2009, Rudolf Pecinovský 143 Charakteristika ►Účel ● Zabezpečit spolupráci již exitujících tříd, tj. tříd, jejichž rozhraní už nemůžeme měnit ● Usnadnit definici nových tříd, v nichž pak nemusíme implementovat celé požadované rozhraní ►Nasazení ● Použití tříd z pevných knihoven v jiných prostředích ● Využití třídy s požadovanou funkčností, ale jiným rozhraním ● Implementace ekvivalence mezi rozhraními ● Doplnění funkcionality třídy na požadovanou rozhraním

144 ICZ Copyright © 2009, Rudolf Pecinovský 144 Adaptér jako rodič adaptované třídy ►Třída Adaptér definuje implicitní implementace všech metod požadovaných rozhraním IPožadované přičemž implicitní verze typicky: ● Vyhazuje UnsupportedOperationException ● Nedělá nic ►Potomci pak mohou definovat pouze ty metody, které se jim „hodí do krámu“ ►Pro klienta potomek implementuje vše

145 ICZ Copyright © 2009, Rudolf Pecinovský 145 Příklad public interface IPosuvný extends IKreslený { //== DEKLAROVANÉ METODY ================================= public Pozice getPozice(); public void setPozice( Pozice pozice ); public void setPozice( int x, int y ); //== VNOŘENÉ TŘÍDY ====================================== public static class Adaptér extends IKreslený.Adaptér implements IPosuvný { public Pozice getPozice(){ throw new UnsupportedOperationException(); } public void setPozice( int x, int y ) { throw new UnsupportedOperationException(); } public void setPozice( Pozice pozice ) { setPozice( pozice.x, pozice.y ); } Metoda s definovatelnou implementací používající vzor Šablonová metoda Metody, o jejichž implementaci se uživatel může rozhodnout podle potřeby Adaptér je definován jako třída vnořená do rozhraní, na něž bude své potomky adaptovat

146 ICZ Copyright © 2009, Rudolf Pecinovský 146 Možná implementace adaptéru – předka public interface IPosuvný extends IKreslený { //== DEKLAROVANÉ METODY ================================= public Pozice getPozice(); public void setPozice( Pozice pozice ); public void setPozice( int x, int y ); //== VNOŘENÉ TŘÍDY ====================================== public static class Adaptér extends IKreslený.Adaptér implements IPosuvný { public Pozice getPozice(){ throw new UnsupportedOperationException(); } public void setPozice( Pozice pozice ){ setPozice( pozice.x, pozice.y ); } public void setPozice( int x, int y ) { throw new UnsupportedOperationException(); } Metoda s definovatelnou implementací používající vzor Šablonová metoda Metody, o jejichž implementaci se uživatel může rozhodnout podle potřeby Adaptér je definován jako vnořená třída rozhraní, na něž bude své potomky adaptovat

147 ICZ Copyright © 2009, Rudolf Pecinovský 147 Adaptovaný objekt jako atribut1/2 ►Pracuje stejně jako ochranný zástupce, pouze s jinou motivací ►Adaptér definuje atribut s odkazem na adaptovaný objekt public class Adaptér implements IPožadované { Existující adaptovaný; public Adaptér(Existující exist) { adaptovaný = exist; }

148 ICZ Copyright © 2009, Rudolf Pecinovský 148 Adaptovaný objekt jako atribut2/2 ►Všechna volání metod „přehrává“ na volání ekvivalentních metod adaptovaného objektu public class Adaptér implements IPožadované { Existující adaptovaný; public Adaptér(Existující exist) { adaptovaný = exist; } public void metoda(Parametr parametr) { Požadovaný požadovaný = uprav(parametr); adaptovaný.jehoMetoda(požadovaný); }

149 ICZ Copyright © 2009, Rudolf Pecinovský 149 Příklady ►Adaptace prostřednictvím předka ● Všechna rozhraní posluchačů java.awt.event.XyzListener deklarující více než jednu metodu mají sdružené třídy java.awt.event.XyzAdapter ►Adaptace prostřednictvím atributu ● Instance třídy Barva z knihovny Tvary jsou jemně upravenými počeštěnými obálkami kolem instance typu java.awt.Color ● Instance třídy Kreslítko z knihovny Tvary jsou zestručněnými počeštěnými obálkami kolem instance typu java.awt.Graphics2D

150 Vaše jistota na trhu IT Strom (Composite)043 ►Sjednocuje typy používaných objektů a umožňuje tak jednotné zpracování každého z nich nezávisle na tom, jedná-li se o atomický (tj. dále nedělitelný) objekt nebo o objekt složený z jiných objektů. Obsah

151 ICZ Copyright © 2009, Rudolf Pecinovský 151 Charakteristika ►Ukazuje, jak vytvořit hierarchii složenou ze dvou druhů objektů: ● Atomických (primitivních) ● Složených (z atomických či dalších složených) ►Většinou tvoří struktura strom, ale není to nutné ►Použití ● Grafické editory vytvářející složité objekty z jednodušších ● Reprezentace tahů a protitahů ve hrách ● Adresářová struktura ● Struktura různých orgranizací ● Implementace nejrůznějších dalších stromových struktur

152 ICZ Copyright © 2009, Rudolf Pecinovský 152 Diagram tříd v návrhovém vzoru Strom ►Doporučuje definovat pro atomické i složené objekty společného rodiče

153 ICZ Copyright © 2009, Rudolf Pecinovský 153 Důsledky použití vzoru ►Zjednodušuje klienta, protože může s atomickými i složenými objekty zacházet jednotně ►Jednodušeji se přidávají nové komponenty ● Díky společnému rodiči je klient automaticky zná ● Je-li rodičem abstraktní třída, může v ní být již řada potřebných metod definována ►Nebezpečí ● Jednoduché přidávání komponent komplikuje verifikaci, že přidávaná komponenta smí být přidána – je třeba použít kontroly za běhu ● Metody ve společném rodiči zvyšují obecnost, ale současně snižují robustnost (nemusí na konkrétního potomka sedět), metody v potomcích naopak

154 Vaše jistota na trhu IT 05 Otevřenost variantním řešením05 ►Tovární metoda (Factory method)051Tovární metoda (Factory method) ►Prototyp (Prototype)052Prototyp (Prototype) ►Stavitel (Builder)053Stavitel (Builder) ►Abstraktní továrna (Abstract factory)054Abstraktní továrna (Abstract factory) Obsah

155 ICZ Copyright © 2009, Rudolf Pecinovský 155 Společný příklad: GoF/Xiaoping: Bludiště ►Bludiště, v němž jsou jednotlivé místnosti ohraničeny stěnami, dveřmi či sousedními místnostmi; každá místnost zná své sousedy na hranicích ►Všechny uvedené objekty jsou potomky součástí bludiště ►Zdroj:

156 Vaše jistota na trhu IT Tovární metoda (Factory method)051 ►Deklaruje rozhraní s metodou pro získání objektu. Rozhodnutí o konkrétním typu vráceného objektu však ponechává na svých potomcích, tj. na překrývajících verzích deklarované metody. Obsah

157 ICZ Copyright © 2009, Rudolf Pecinovský 157 Charakteristika ►Oproti jednoduché tovární metodě bývá standardní tovární metoda definována jako abstraktní metoda společného předka, tj. definuje se pouze, že potomci definují metodu vracející objekty daného typu ►Skutečnou podobu metody a tím i to, co přesně bude metoda vracet, definují až potomci ►Potomci definují nejenom vlastnosti vytvářeného objektu, ale především jeho skutečný typ – občas bývá označována jako virtuální konstruktor ►Umožňuje oddělení proměnného a neměnného kódu ►Typické příklady: Iterator, Graphics

158 ICZ Copyright © 2009, Rudolf Pecinovský 158 Diagram tříd vzoru Tovární metoda

159 ICZ Copyright © 2009, Rudolf Pecinovský 159 Aplikace tovární metody v knihovně kontejnerů

160 ICZ Copyright © 2009, Rudolf Pecinovský 160 Kolekce – továrny na iterátory

161 ICZ Copyright © 2009, Rudolf Pecinovský 161 Vlastnosti ►Umožňuje ignorovat implementaci a soustředit se na rozhraní, tj. na klíčové vlastnosti objektu ►Zapouzdřuje vytváření instancí; při jejím použití se není třeba starat o to, jak použitá instance vznikne ►Umožňuje, aby aplikace byla schopna vytvářet instance i od tříd, které ještě nezná ►Třída nemusí vždy tovární metodu definovat, často ji stačí převzít od předka ►Třídy, jejichž instance tovární metody vracejí, jsou často definovány jako interní třídy „továrních tříd“ ►Někdy tovární metody používají klonování – viz dále

162 ICZ Copyright © 2009, Rudolf Pecinovský 162 Příklad GoF/Xiaoping: Bludiště

163 ICZ Copyright © 2009, Rudolf Pecinovský 163 Příklad GoF/Xiaoping: Bludiště src1/2 public class HarryPotterMazeGameCreator extends MazeGameCreator { public Wall makeMaze() { return new HarryPotterMaze(); } public Wall makeWall() { return new HarryPotterWall(); } public Room makeRoom(int roomNumber) { return new HarryPotterRoom(roomNumber); } public Door makeDoor(Room room1, Room room2) { return new HarryPotterDoor(room1, room2); }

164 ICZ Copyright © 2009, Rudolf Pecinovský 164 Příklad GoF/Xiaoping: Bludiště src2/2 public class MazeGameCreator { public Maze createMaze() { Maze maze = makeMaze(); Room room1 = makeRoom(1); //... Door door1 = makeDoor(room1, room2); //... door1.setOpen(true); //... room1.setSide(Direction.NORTH, door8; //... maze.addRoom(room1); ; //... return maze; } public Maze makeMaze() { return new Maze(); } public Wall makeWall() { return new Wall(); } public Room makeRoom( int roomNumber) { /*...*/ } public Door makeDoor(Room room1, Room room2) {/*...*/} Implicitní definice mohou být nahrazeny abstraktními

165 Vaše jistota na trhu IT Prototyp (Prototype)052 ►Objekt definuje tovární metodu, která bude vytvářet jeho kopie. V programu je pak možno místo přímého volání konstruktoru využívat volání kopírovací tovární metody připraveného prototypu. Obsah

166 ICZ Copyright © 2009, Rudolf Pecinovský 166 Tři cesty k vytvoření objektu ►Konstruktor ● Jediná cesta, jak vytvořit skutečně novou instance ►Klonování ● Vytvoření kopie nějaké dříve vytvořené instance ►Serializace – deserializace ● Načtení kopie nějaké dříve vytvořené instance z nějakého úložiště

167 ICZ Copyright © 2009, Rudolf Pecinovský 167 Diagram tříd návrhového vzoru Prototyp ►Můžeme definovat i vlastní mechanizmus klonování, ale využití podpory systému (implementace rozhraní Cloneable ) je většinou výhodnější

168 ICZ Copyright © 2009, Rudolf Pecinovský 168 Implementace klonování v Javě1/2 ►Klonovací metoda nebývá většinou obálka kolem konstruktoru, ale metoda řešící kopírování vzorové instance na systémové úrovni ►Metodu clone() definuje třída Object, od které ji všichni dědí ►Systémová verze metody je ochotna „zkopírovat“ pouze instanci třídy implementující rozhraní Cloneable ►Systémová verze je definována jako protected, takže ji bez zveřejnění nemůže použít kdokoliv

169 ICZ Copyright © 2009, Rudolf Pecinovský 169 Implementace klonování v Javě2/2 ►Typická podoba zveřejňovaci definice: public Object clone() { return super.clone(); } ►Dokud třída neimplementuje Cloneable, systémová definice se s ní nebaví ►Třída nemusí používat super.clone(), může v případě potřeby definovat vlastní verzi definovanou jako obálku kopírovacího konstruktoru ►Nepotřebuje-li třída super.clone(), nemusí implementovat Cloneable

170 ICZ Copyright © 2009, Rudolf Pecinovský 170 Duch definice ve třídě Object public Object clone() { if (!(this instanceof Cloneable)) { throw new CloneNotSupportedException(); } //Vyhradí místo v paměti Object clone = allocateNew( this ); //Zkopíruje do něj obsah instance byteCopy( this, clone ); return clone; }

171 ICZ Copyright © 2009, Rudolf Pecinovský 171 CloneNotSupportedException ►Aby nebylo v programech třeba ošetřovat možný výskyt kontrolované výjimky CloneNotSupportedException, lze po objektech požadovat, aby implementovali rozhraní, v němž je metoda clone() deklarována jako metoda nevyhazující žádnou kontrolovanou výjimku ►Používáme-li instance knihovních tříd, které takovéto rozhraní neimplementují, můžeme je přizpůsobit našim požadavkům prostřednictvím adaptéru

172 ICZ Copyright © 2009, Rudolf Pecinovský 172 Mělká a hluboká kopie ►Mělká kopie přebírá od originálu jeho odkazy, tj. kopie odkazuje na ty samé objekty, jako originál ►Hluboká kopie definuje také kopie odkazovaných objektů ►Odkazované objekty mohou být opět zkopírovány mělce či hluboce ►To, zda bude objekt kopírován mělce či hluboce, si objekt definuje sám ►Systémová verze kopíruje mělce

173 ICZ Copyright © 2009, Rudolf Pecinovský 173 Kdy co ►Obecně bývá výhodnější ● Využití metody clone() při používání mělkých kopií ● Využití speciální tovární metody volající konstruktor při používání hlubokých kopií ►Nemusí tomu tak ale být vždy ►Návrhový vzor Prototyp není fixován na metodu clone() ; místo ní můžeme pro vytváření kopií definovat i vlastní metodu

174 ICZ Copyright © 2009, Rudolf Pecinovský 174 Doporučené invarianty ►Klon nemusí být povinně kopie, měly by však dodržet následující invarianty: x.clone() != x x.clone().equals(x) x.clone().getClass() == x.getClass() ►Teoreticky je možno definovat metodu, která tyto invarianty nedodržuje, ale musí pro to být nějaký pádný důvod a je třeba zabezpečit, aby s tím zbytek programu počítal

175 ICZ Copyright © 2009, Rudolf Pecinovský 175 Kopírování instancí hodnotových typů ►Je např. možno využít skutečnosti, že nás nezajímá skutečná kopie, ale kopie hodnoty – pak lze definovat: public Object clone() { return this; } ►Platí pouze pro neměnné typy ►Porušuje doporučen invariant x.clone() != x, ale u hodnotových typů se většinou na rozdíly instancí nehledí

176 ICZ Copyright © 2009, Rudolf Pecinovský 176 Další vlastnosti klonování ►Klonovací metoda se chová jako zvláštní tovární metoda, kde tovární třídu zastupuje klonovaná instance ►Umožňuje, aby aplikace byla schopna vytvářet instance i od tříd, které ještě nezná, výrazně efektivněji než při použití reflexe ►Klonování umožňuje definovat i pseudotřídy tvořené skupinami instancí stejné třídy ● Ve virtuálním světe mám objekty definované jako mnohotvary, jejichž instance se mohou sdružovat do pseudotříd: osoba – auto – autobus ● Takovéto pseudotřídy mohou vnikat dynamicky za běhu

177 ICZ Copyright © 2009, Rudolf Pecinovský 177 Použití v praxi ►Vracení interního pole či jiného kontejneru ● Vrácením klonu zabezpečíme, že žadatel nemá šanci obsah pole změnit ►Zkrácení seznamu parametrů ● Mám-li definovanou instanci, která může sloužit jako vzor, nemusím při vytváření jejích kopií předávat parametry

178 ICZ Copyright © 2009, Rudolf Pecinovský 178 Příklad GoF/Xiaoping: Bludiště GoTo FactoryMethod

179 ICZ Copyright © 2009, Rudolf Pecinovský 179 Příklad GoF/Xiaoping: Bludiště src public class MazePrototypeFactory extends MazeFactory { public MazePrototypeFactory( Maze mazePrototype, Wall wallPrototype, Room roomPrototype, Door doorPrototype) { this.mazePrototype = mazePrototype; this.wallPrototype = wallPrototype; this.roomPrototype = roomPrototype; this.doorPrototype = doorPrototype; } public Maze makeMaze() { try { return (Maze) mazePrototype.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException( e ); }

180 Vaše jistota na trhu IT Stavitel (Builder)053 ►Odděluje konstrukci složitého objektu (tj. postup jeho tvorby) od jeho vnitřní reprezentace. Tím umožňuje využít stejného konstrukčního postupu pro různé vnitřní reprezentace konstruovaných objektů. Obsah

181 ICZ Copyright © 2009, Rudolf Pecinovský 181 Charakteristika ►Účelem vzoru Stavitel je umožnit využití stejného konstrukčního postupu pro různé vnitřní reprezentace konstruovaných objektů ►Návrhový vzor stavitel se nesoustřeďuje na vlastní vytvoření a „dodání“ objektu, ale na postup jeho tvorby

182 ICZ Copyright © 2009, Rudolf Pecinovský 182 Řídící objekt × výkonné objekty ►V návrhovém vzoru vystupuje vedle sebe řídící objekt a výkonné objekty ►Řídící objekt má na starosti dodržení správného postupu vytvoření požadovaného objektu ►Výkonné objekty mají na starosti vytvoření některých detailů podle pokynů řídícího objektu ►V některých případech jsou výkonné objekty schopny vytvořit podle návodu řídícího objektu celý požadovaný objekt

183 ICZ Copyright © 2009, Rudolf Pecinovský 183 Diagram tříd návrhového vzoru Stavitel

184 ICZ Copyright © 2009, Rudolf Pecinovský 184 Výkonné objekty ►Pro různé druhy vytvářených objektů (např. pro jejich různé vnitřní reprezentace) se používají různé výkonné objekty, tj. objekty, které jsou instancemi různých tříd ►Aby mohly být výkonné objekty jednotně používány, implementují společné rozhraní, případně mají společného rodiče ►Každý výkonný objekt je typicky schopen vytvořit kteroukoliv z částí požadovaných řídícím objektem. Jednotlivé výkonné objekty se liší pouze v tom, jak tuto část vytvoří

185 ICZ Copyright © 2009, Rudolf Pecinovský 185 Použití: ►Je ‑ li algoritmus tvorby objektu nezávislý na použité vnitřní reprezentaci ►Mají ‑ li vytvářené objekty složitější vnitřní strukturu a budují ‑ li se proto v několika fázích ►Je ‑ li vhodné použít řídící objekt současně jako správce zdrojů používaných při tvorbě daných objektů

186 ICZ Copyright © 2009, Rudolf Pecinovský 186 Příklad: Sázecí program package rup.česky.vzory._24_stavitel.text; public interface ISázecíStroj //Výkonný { public String běžný ( String text ); public String tučný ( String text ); public String šikmý ( String text ); public String odstavec( String text ); public String dokument( String text ); }

187 ICZ Copyright © 2009, Rudolf Pecinovský 187 Sázecí program – diagram tříd Řídící objekt Výkonný objekt Autor vyrobí text složený z odstavců a předá jej sazeči spolu se sázecím strojem, jehož prostřednictvím chce text vysadit Ukázka

188 ICZ Copyright © 2009, Rudolf Pecinovský 188 Příklad GoF/Xiaoping: Bludiště Výkonný objekt Řídící objekt GoTo FactoryMethod GoTo Prototype

189 ICZ Copyright © 2009, Rudolf Pecinovský 189 Příklad GoF/Xiaoping: Bludiště src1/2 public interface MazeBuilder { public void newMaze(); public Maze getMaze(); public void buildRoom(int roomNumber); public void buildDoor(int roomNumber1, int roomNumber2, Direction dir, boolean open); } public class MazeGameBuilder //Director { public static Maze createMaze(MazeBuilder builder) { builder.newMaze(); builder.buildRoom(1); builder.buildRoom(2); //... builder.buildDoor(1, 2, Direction.WEST, true); builder.buildDoor(2, 3, Direction.WEST, false); //... return builder.getMaze(); }

190 ICZ Copyright © 2009, Rudolf Pecinovský 190 Příklad GoF/Xiaoping: Bludiště src2/2 public class FactoryMazeBuilder implements MazeBuilder { public FactoryMazeBuilder(MazeFactory factory) { this.factory = factory; } public void newMaze() { maze = factory.makeMaze(); } public Maze getMaze() { return maze; } public void buildRoom(int roomNumber) { if (maze == null) newMaze(); Room room = factory.makeRoom(roomNumber); //... maze.addRoom(room); } public void buildDoor(int roomNumber1, int roomNumber2, Direction dir, boolean open) { //... } //... }

191 Vaše jistota na trhu IT Abstraktní továrna (Abstract factory)054 ►Definuje rozhraní pro tvorbu celé rodiny souvisejících nebo závislých objektů, a tím odděluje klienta od vlastního procesu vytváření objektů. Obsah

192 ICZ Copyright © 2009, Rudolf Pecinovský 192 Charakteristika ►Návrhový vzor Abstraktní továrna řeší problém, kdy je třeba vybrat mezi několika sadami tříd, jejichž instance budou vystupovat v programu ►Typickým použitím Abstraktní továrny je volba celkového vzhledu a chování (look and feel) GUI ►Instance vracené jednotlivými metodami mohou být jak různého, tak stejného typu ►Někdy je označován jako Kit (souprava, stavebnice)

193 ICZ Copyright © 2009, Rudolf Pecinovský 193 Schéma Principiální schéma vzoru Abstraktní tovární metoda

194 ICZ Copyright © 2009, Rudolf Pecinovský 194 Implementace ►Při implementaci Abstraktní továrny se často používá vzor Tovární metoda ►Jednotlivé používané „tovární instance“ bývají definovány jako jedináčci ►Návrhový vzor Abstraktní továrna neumožňuje jednoduše přidávat další rozhraní, jejichž instance budou „tovární instance“ dodávat; řešení s univerzální tovární metodou snižuje robustnost systému ►Při implementaci Abstraktní továrny se často používá vzor Prototyp

195 ICZ Copyright © 2009, Rudolf Pecinovský 195 Diagram tříd objektů virtuálního světa

196 ICZ Copyright © 2009, Rudolf Pecinovský 196 Diagram tříd simulace virtuálního světa

197 ICZ Copyright © 2009, Rudolf Pecinovský 197 Příklad GoF/Xiaoping: Bludiště GoTo FactoryMethod GoTo Prototype GoTo Builder

198 ICZ Copyright © 2009, Rudolf Pecinovský 198 Příklad GoF/Xiaoping: Bludiště src public class MazeGameAbstractFactory { public static Maze createMaze(MazeFactory factory) { Maze maze = factory.makeMaze(); Room room1 = factory.makeRoom(1); Room room2 = factory.makeRoom(2); //... Door door1 = factory.makeDoor(room1, room2); Door door2 = factory.makeDoor(room2, room3); //... ►Konstruktor abstraktní továrny dostane konkrétní továrnu jako parametr a tu pak žádá o vytvoření jednotlivých objektů

199 Vaše jistota na trhu IT 06 Ochrana před rozrůstáním06 ►Dekorátor (Decorator) 061Dekorátor (Decorator) ►Řetěz odpovědnosti (Chain of responsibility)062Řetěz odpovědnosti (Chain of responsibility) ►Pozorovatel (Observer)063Pozorovatel (Observer) ►Prostředník (Mediator)064Prostředník (Mediator) Obsah

200 Vaše jistota na trhu IT Dekorátor (Decorator) 061 ►Přidává další přídavnou funkcionalitu k objektu tak, že objekt „zabalí“ do jiného objektu, který má na starosti pouze přidanou funkcionalitu a zbytek požadavků deleguje na „zabalený“ objekt. Tím umožňuje přidávat funkčnost dynamicky a zavádí flexibilní alternativu k dědění. Obsah

201 ICZ Copyright © 2009, Rudolf Pecinovský 201 Motivace ►V knihovně potřebujeme nabízet třídy‘ poskytující různé kombinace funkcionalit ►Při nutnosti nabízet téměř všechny možné kombinace roste počet potřebných tříd kombinatoricky = neúnosně ►S každou další přidanou funkcionalitou musíme přidat násobek dosud existujících tříd ►S každou přidanou základní třídou musíme přidat i třídy pro možné kombinace přidaných funkcionalit

202 ICZ Copyright © 2009, Rudolf Pecinovský 202 Charakteristika ►Návrhový vzor Dekorátor umožňuje snížit kombinatoricky rostoucí počet tříd ►Každá dodaná funkčnost je implementována jako „ozdobení“ (dekorování) jiného objektu ►Dekorátor rozšiřuje (zdobí) objekt, ne třídu; na rozdíl od statické dědičnosti pracuje dynamicky ►Základní třídy i dekorátory mají společného rodiče ►Příklad ● Knihovna proudů java.io (s bufferem, řádkováním, daty, …) ● swing (pole, s posuvníkem, s okrajem, s oběma, …)

203 ICZ Copyright © 2009, Rudolf Pecinovský 203 Implementace1/2 ►Využít postupu aplikovaného u návrhového vzoru Adaptér a zabalit objekt do objektu poskytujícího novou funkcionalitu, který tak původní objekt ozdobí (dekoruje) novou funkcionalitou ►Pro každou novou funkcionalitu pak bude stačit přidat pouze jedinou obalovou (dekorující) třídu ►Konstruktor dekorátoru přebírá dekorovaný objekt jako parametr a „obalí“ jej vlastními schopnostmi ►Dekorátor většinou přidává metody, které se starají o jím přidanou funkčnost. Může ale také pouze překrýt metody svých předků a definovat je pro daný účel efektivněji ►Požadavky nesouvisející s dodatečnou funkčností předá dekorátor dekorovanému objektu a vrátí obdržený výsledek

204 ICZ Copyright © 2009, Rudolf Pecinovský 204 Implementace2/2 ►Přidávané funkcionality je možné kumulovat, tj. zabalený objekt lze znovu zabalit do objektu přidávajícího další funkcionalitu ● Výsledný objekt lze vytvářet postupně: AAuto benzin = new Benzin(); AAuto abs = new ABS( benzin ); AAuto auto = new Automat(abs); ● Nebo najednou AAuto auto1 = new Automat( new ABS(new Benzin()) ); AAuto auto2 = new Automat( new ABS( new Benzin()) ); ►Dekorátory mají někdy ještě vlastního rodiče se společnou implementací. ►Ten pak bývá koncipován jako adaptér nabízející implicitní funkčnost: delegování metod na obalený objekt a vracení obdržených výsledků

205 ICZ Copyright © 2009, Rudolf Pecinovský 205 Struktura tříd při implementaci vzoru Dekorátor ►Dekorátor pracuje jako obálka kolem dekorovaného objektu zabezpečující dodatečnou funkčnost ►Občas bývá nazýván Wrapper

206 ICZ Copyright © 2009, Rudolf Pecinovský 206 Využití adaptéru ►Pro všechny dekorující třídy lze definovat společného rodiče, který volání neupravených metod převede na volání odpovídajících metod dekorovaného objektu ►Každá nově přidaná základní třída automaticky získává všechny v úvahu přicházející funkcionality

207 ICZ Copyright © 2009, Rudolf Pecinovský 207 Společný rodič dekorujících tříd public class Dekorovaný extends AAuto { AAuto dekorovaný; public Dekorovaný(AAuto auto) { dekorovaný = auto; } public void zrychliNa(int rychlost, int doba) { dekorovaný.zrychliNa( rychlost, doba ); } public void zpomalNa(int rychlost, int dráha) { dekorovaný.zpomalNa( rychlost, dráha ); } public void zabrzdiNa(int dráha) { dekorovaný.zabrzdiNa( dráha ); }

208 ICZ Copyright © 2009, Rudolf Pecinovský 208 Koncepce čtení a zápisu dat v java.io

209 ICZ Copyright © 2009, Rudolf Pecinovský 209 Příklady java.io.FilterInputStream java.io.FilterOutputStream java.io.FilterReader java.io.FilterWriter package rup.česky.vzory._26_dekorátor; ASCIIReader ASCIIWriter MultiWriter

210 ICZ Copyright © 2009, Rudolf Pecinovský / – ►Výhody ● Pracuje dynamicky ● Lze je vrstvit jeden na druhý ● Není potřeba předvídat všechny potřeby klienta ►Nevýhody ● Dekorátor není dekorovaný objekt => prostřednictvím dekorátoru není možné volat metody, s nimiž dekorátor nepočítal ● Postupná delegace volání může mírně zpomalit kód ● Dekorovaný objekt je stále obecně dostupný => je třeba hlídat, kdy oslovuji vlastní objekt a kdy dekorovaný objekt

211 Vaše jistota na trhu IT Řetěz odpovědnosti 062 (Chain of responsibility) ►Umožňuje, aby zaslaný požadavek zpracoval jiný objekt než ten, kterému byl zadán. Doporučuje objekty zřetězit tak, aby objekt, který není schopen požadavek zpracovat, mohl požadavek předat dalšímu objektu v řetězu. Obsah

212 ICZ Copyright © 2009, Rudolf Pecinovský 212 Charakteristika ►Návrhový vzor Řetěz odpovědnosti ukazuje možné řešení úlohy, vyžadující zaslání zprávy některému ze skupiny objektů, aniž by bylo předem známo, který z nich je v daný okamžik ten pravý ►Využívá se v případě, kdy není dopředu jasné, koho oslovit ►Vzor minimalizuje provázanost mezi odesilatelem a příjemcem zprávy ►Umožňuje měnit řetěz dynamicky za chodu

213 ICZ Copyright © 2009, Rudolf Pecinovský 213 Proč řetěz ODPOVĚDNOSTI ►Příjemci jsou ve frontě a zprávu si předávají, dokud ji někdo nezpracuje ►Instance, kterou oslovíme, je zodpovědná za to, že na zprávu správně zareaguje Ona ale tuto svoji odpovědnost přehraje na další instanci v řetězu navzájem na sebe napojených instancí

214 ICZ Copyright © 2009, Rudolf Pecinovský 214 Aplikace ►Typické použití: GUI, kontextová nápověda ►Obecně ve stromových strukturách: když se nějakého uzlu na něco zeptáme a on nebude umět odpovědět, tak přehraje požadavek na svůj rodičovský uzel, nebude ‑ li to vědět ani on, přehraje to opět na svého rodiče, a tak to poběží dál, až to v případě neschopnosti kohokoliv odpovědět skončí někde v koření celého stromu ►Může to být i obráceně: rodič se ptá svých potomků, neumí-li někdo na danou zprávu odpovědět; potomek opět může rekurzivně poslat dotaz dál

215 ICZ Copyright © 2009, Rudolf Pecinovský 215 Implementace ►Skupina instancí, z nichž bude některá reagovat, je navzájem propojena odkazy do řetězu (seznamu) ►Neumí ‑ li oslovený objekt reagovat, předá požadavek dalšímu v řetězu s nadějí, že on to dokáže ►Řetěz umožňuje dynamicky měnit konečného adresáta dané zprávy ►Instance v řetězu mohou být různých typů – pak je vhodné aplikovat vzor StromStrom

216 Vaše jistota na trhu IT Pozorovatel (Observer), Posluchač (Listener)063 ►Zavádí vztah mezi objekty (pozorovateli) reagujícími na změnu stavu (pozorovaného) objektu nebo na jím sledované události. Pozorovatelé se u pozorovaného objektu přihlásí a ten je pak na každou změnu svého stavu či výskyt události upozorní. Obsah

217 ICZ Copyright © 2009, Rudolf Pecinovský 217 Motivace Objekt čekající na výskyt nějaké události – má dvě možnosti: ►Neustále se ptát iniciátora události, zda už nastala ● Oslík v 2. dílu Shreka se neustále ptá „Už tam budem?“ ● Řidič čekající na zelenou neustále sleduje semafor ►Dohodne se s iniciátorem, že dohodnutým způsobem oznámí, až událost nastane ● V lůžkovém vlaku vás průvodčí vzbudí před cílovou stanicí ● Řidič na semaforu v klidu čte mapu v očekávání, že ti za ním na něj zatroubí ● SMS oznámí příchod peněz na konto ►Návrhový vzor Pozorovatel řeší problém druhým způsobem, je však třeba dohodnout způsob oznámení výskytu události

218 ICZ Copyright © 2009, Rudolf Pecinovský 218 Charakteristika ►Bývá někdy označován jako vzor Posluchač (Listener) nebo jako vzor vydavatel—předplatitel (publisher—subscriber) ►Ukazuje, jak zabezpečit, aby se objekt včas dozvěděl o události, na kterou čeká, aniž by musel obtěžovat jejího iniciátora neustálými dotazy ►Pozorovatel se přihlásí u pozorovaného objektu, a ten mu při vzniku očekávané události pošle o této události zprávu

219 ICZ Copyright © 2009, Rudolf Pecinovský 219 Posluchač – implementace ►Posluchač (pozorovatel, předplatitel) se musí přihlásit u vysílače (pozorovaného, vydavatele) ►Vysílač je ochoten přijmout přihlášku pouze od objektů implementujících rozhraní definující jak objektu oznámit, že došlo k očekávané události ►Posluchač se po přihlášení o událost dál nestará a hledí si svého ►Až vysílač zavolá dohodnutou metodu, pak zareaguje ►Událostmi řízené programování

220 ICZ Copyright © 2009, Rudolf Pecinovský 220 Implementace ve standardní knihovně ►Ve standardní knihovně je pro aplikaci tohoto vzoru připraveno rozhraní java.util.Observer a třída java.util.Observable ►Použití implementace ze standardní knihovny vyžaduje definici potomka třídy Observable ►Rozhraní Observer deklaruje metodu update(Observable, Object) ● První parametr předává odkaz na pozorovaný objekt, který metodu zavolal. Je definován proto, aby mohl být jeden pozorovatel přihlášen u několika pozorovaných objektů ● Druhý parametr slouží jako schránka na případné parametry

221 ICZ Copyright © 2009, Rudolf Pecinovský 221 Strategie implementace ►Můžeme použít tažnou nebo tlačnou strategii: ►Při tažné strategii si pozorovatel říká pozorovanému objektu o potřebné parametry, ►Při tlačné strategii předá pozorovaný objekt pozorovateli všechny parametry při volání upozorňovací metody

222 ICZ Copyright © 2009, Rudolf Pecinovský 222 Příklad: IListener + IBroadcast public interface IListener { public void update( IBroadcast bc, Object... args ); } public interface IBroadcast { public void addListener( L lis ); public void removeListener( L lis ); public void removeAllListeners(); }

223 Vaše jistota na trhu IT Prostředník (Mediator)064 ►Odstraní vzájemné vazby mezi řadou navzájem komunikujících objektů tím, že zavede objekt, který bude prostředníkem mezi komunikujícími objekty. Tím zruší přímou vzájemnou závislost komunikujících objektů a umožní upravovat chování každého z nich nezávisle na ostatních. Obsah

224 ICZ Copyright © 2009, Rudolf Pecinovský 224 Motivace ►Objekty v jednoduché grafické aplikaci se při pohybu nejprve smažou v původní pozici, aby se pak nakreslily v nové; při tom občas odmažou i část svých kolegů ►Aby objekt mohl zrekonstruovat svůj obraz, musel by mu někdo poslat zprávu, že byl (byť částečně) smazán ►Vysílač je vždy závislý na příjemci, protože změna jeho rozhraní může ovlivnit požadovaný způsob zasílání zpráv ►Když bude každý umět každému poslat zprávu, velmi se zvýší počet vzájemných závislostí, které zhoršují spravovatelnost ● Každá změna nás nutí zkontrolovat všechny závislé objekty ● Musí-li se změnit závislý objekt, dominovým efektem se problém propaguje na všechny objekty, které jsou na něm závislé

225 ICZ Copyright © 2009, Rudolf Pecinovský 225 Doporučené řešení ►Obdobný problém byl i u telefonů – obdobné je i řešení ● Telefony také nejsou spojeny každý s každým, ale spojují se prostřednictvím ústředny ►Definujeme objekt prostředníka, který zprostředkovává veškerou komunikaci objektů ● Vzájemné závislosti objektů se tak omezí na závislost na prostředníku ►V našem projektu nahradíme plátno správcem plátna ● Má na starosti správný vzhled ● Když objekt mění svoji podobu, řekne správci ● Správce pak požádá o překreslení všechny, jichž se to týká ►Prostředník je většinou implementován aplikací návrhového vzoru Pozorovatel

226 ICZ Copyright © 2009, Rudolf Pecinovský 226 Charakteristika ►Doporučuje zjednodušit vzájemnou komunikaci mezi mnoha objekty zavedením prostředníka, na kterého se budou všichni obracet a který jejich zprávy předá požadovanému adresátu ►Pro přeposílání obdržených zpráv bývá často použit návrhový vzor Pozorovatel ►Návrhový vzor Prostředník je výhodné aplikovat: ● je ‑ li vzájemná komunikace objektů složitá, nebo ● je ‑ li třeba použít komunikující objekty také samostatně ►Oddělením komunikujících objektů docílíme toho, že je můžeme měnit nezávisle na sobě Motivace

227 ICZ Copyright © 2009, Rudolf Pecinovský 227 Implementace ►Modifikaci režimu komunikace lze zabezpečit např. definováním dceřiné třídy prostředníka ►Posílaná zpráva je definována jako metoda prostředníka jejímiž parametry jsou součásti zprávy ►Součástí zprávy posílané prostředníku může být i odkaz na příjemce či odesilatele ►Prostředník někdy slouží jako distributor zpráv předávaných všem kolegům (viz SprávcePlátna ) – pak většinou implementuje i vzor PozorovatelPozorovatel

228 ICZ Copyright © 2009, Rudolf Pecinovský 228 Výhody × nevýhody ►Zjednodušuje protokol – nahrazuje vazby m:n vazbami 1:m, které jsou jednodušší na pochopení ►Ruší vazby mezi kolegy a usnadňuje tak jejich znovupoužití ►Odděluje kooperaci mezi objekty od jejich samostatného chování ►Soustřeďuje distribuované chování na jedno místo – to bývá často současně nevýhodou, protože vzniká složitý (příp. supersložitý) objekt – prostředník

229 ICZ Copyright © 2009, Rudolf Pecinovský 229 Použití ►GUI, je-li chování prvků dialogového okna závislé na nastavení některých jiných prvků; při větším množství křížových vazeb je výhodné použít prostředníka ►Distribuce požadavků konfiguračních souborů nebo jinak nastavených parametrů ►Příklad: Plátno × SprávcePlátna Plátno × SprávcePlátna

230 Vaše jistota na trhu IT 07 Dodatečné úpravy 07 ►Most (Bridge)071Most (Bridge) ►Strategie (Strategy)072Strategie (Strategy) ►MVC (Model – View – Controller)073MVC (Model – View – Controller) ►Návštěvník (Visitor)074Návštěvník (Visitor) ►Pamětník (Memento)075Pamětník (Memento) ►Interpret (Interpreter)076Interpret (Interpreter) Obsah

231 Vaše jistota na trhu IT Most (Bridge)071 ►Zavedením rozhraní odděluje abstrakci zprostředkovávající nějakou službu od implementace této služby, takže lze obě dvě měnit nezávisle na sobě. Obsah

232 ICZ Copyright © 2009, Rudolf Pecinovský 232 Charakteristika ►Řeší situaci, kdy klient komunikuje se třídou, která je pouze zprostředkovatelem (abstrakcí) nabízené služby. Vlastní realizaci služby má na starosti jiná třída (implementace) ►Návrhový vzor Most doporučuje vložit mezi abstrakci a implementaci rozhraní. Tím je od sebe oddělí a umožní je nezávisle na sobě měnit ►Aplikace vzoru Most umožní definovat implementaci např. v konfiguračním souboru ►Návrhový vzor Most se uplatňuje např. při návrhu ovladačů

233 ICZ Copyright © 2009, Rudolf Pecinovský 233 Implementace ►Při implementaci tohoto vzoru je třeba: ● definovat oddělující rozhraní, ● definovat implementaci, ● definovat, jak abstrakce získá odkaz na implementaci, ● definovat klienta, ● vše rozběhnout

234 ICZ Copyright © 2009, Rudolf Pecinovský 234 Klasicky navržená kalkulačka ►Klasický přístup ● Odděluje se návrh CPU and GUI; – Třídu GUI navrhuje vyučující – Třídu CPU navrhují studenti ● Stisk tlačítka z každé skupiny volá partnerskou metodu v CPU ►Třídy jsou těsně provázané což má své nepříjemné důsledky: ● S každou změnou definice CPU je třeba změnit definic GUI a naopak ● Každá verze studentského zadání vyžaduje vlastní verzi definice GUI ● Chceme-li po studentech, aby u zkoušky svoji třídu upravili, musíme příslušně upravit i námi definované GUI ►Uvedený přístup je nutný v případě neznají-li studenti rozhraní

235 ICZ Copyright © 2009, Rudolf Pecinovský 235 Po aplikaci vzoru Most ►Třída CPU implementuje rozhraní ICPU deklarující tři metody: ● RozměrKláves getRozměr() ● List getPopisky() ● String stisknuto(String label) ►Konstruktor třídy GUI ● Dostane instanci of CPU jako parametr ● Zeptá se na požadovaný rozměr klávesnice a seznam požadovaných popisků tlačítek ● Připraví GUI podle obdržených požadavků ►Běh programu: ● Instance GUI zjistí, jaké tlačítko bylo stisknuto a zašle instanci CPU zprávu s jeho popiskem ● Instance CPU zjistí, co stisk znamená, a vrátí GUI nový obsah displeje

236 ICZ Copyright © 2009, Rudolf Pecinovský 236 Co jsme tím získali ►GUI může spolupracovat s různými CPU; stačí, aby spolupracující CPU implementovala rozhraní ICPU ►Přiblížíme studentům význam a použití rozhraní ►Ukážeme, že tvůrce GUI nemusí znát spolupracující CPU předem, instance GUI se ji může dozvědět až při svém zrodu ►Můžeme do CPU svobodně přidávat další a další funkce, aniž bychom museli jakkoliv upravovat třídu GUI ►Můžeme připravit automatické testy

237 ICZ Copyright © 2009, Rudolf Pecinovský 237 ►Testovací třída se bude tvářit, že je zvláštní GUI ►Třída Verze dodá požadovanou sadu popisků spolu s testy definujícími požadované reakce na stisk kláves ►Rozhraní ICPU rozšíříme o metodu vracející pořadí řešeného zadání int getZadání() ►Můžeme přidat značkovací rozhraní IGUI, jež budou implementovat třídy, které se chtěji vydávat za GUI Testování sady programů

238 Vaše jistota na trhu IT Strategie (Strategy)072 ►Definuje množinu vyměnitelných objektů (algoritmů) řešících zadanou úlohu (tj. objektů se stejným rozhraním) a umožňuje mezi nimi dynamicky přepínat. Obsah

239 ICZ Copyright © 2009, Rudolf Pecinovský 239 Charakteristika ►Ukazuje, jak je možno zabezpečit přepínání použitých algoritmů za chodu programu ►Oproti vzoru Most se nezabývá výměnou části programu, ale přepínáním mezi několika částmi, které jsou (většinou trvalou) součástí programu ►Vzor se nezaměřuje na architekturu systému, ale na jeho chování

240 ICZ Copyright © 2009, Rudolf Pecinovský 240 Strategie × Stav ►Oproti vzoru Stav není přepínání interní záležitostí modulu, ale pracuje na objednávku klienta ►Společným „rodičem“ jednotlivých stavů nemusí být jen rozhraní, ale může jím být i třída implementující implicitní verze metod ►Tento společný rodič může aplikovat i vzor Šablonová metoda

241 ICZ Copyright © 2009, Rudolf Pecinovský 241 Kalkulačka schopná přepínat režimy

242 ICZ Copyright © 2009, Rudolf Pecinovský 242 Super CPU – DP Strategy ►Použitím vzoru Most uvolníme cestu dalším rozšířením ● Můžeme definovat CPU, které nebudou pracovat pouze s běžnými čísly, ale budou schopny pracovat s čísly v různých soustavách, se zlomky, komplexními čísly, vektory, symboly, … ● Umožním definici SuperCPU, která bude umět přepínat mezi různými CPU ►Přidaná SuperCPU demonstratuje užití návrhového vzoru Strategie

243 ICZ Copyright © 2009, Rudolf Pecinovský 243 Super CPU – DP Strategy

244 Vaše jistota na trhu IT MVC (Model – View – Controller) 073 ►Odděluje část programu mající na starosti předzpracování příkazů uživatele (tj. zjištění, co od programu vlastně chce), od částí zabezpečujících logiku programu, která uživatelovy příkazy zpracovává, a části, která má na starosti zobrazení výsledků. Obsah

245 ICZ Copyright © 2009, Rudolf Pecinovský 245 Charakteristika ►Vzor Model – Pohled – Ovládání (MPO); anglicky Model – View – Controller (MVC) je většinou považován za skupinu vzorů ►Doporučuje rozdělit do samostatných modulů části programu zabývající se ● předzpracováním požadavků uživatele, ● vlastní logikou programu a ● prezentací získaných výsledků ►Do části zabývající se prezentací výsledků patří nejenom vlastní GUI, ale často i kód, který data pro tuto prezentaci připravuje

246 ICZ Copyright © 2009, Rudolf Pecinovský 246 Přínosy použití vzoru ►Snadná implementace zadávání požadavků různými způsoby (klávesnice, myš, pero, hlas, …) ►Možnosti různých podob prezentace výsledků (tabulka, graf, mluvené slovo, …) ►Poznámka: Změny požadavků na způsob zadávání požadavků a prezentaci výsledů patří k nejčastějším ►Usnadnění případných budoucích změn ►Přenositelnost mezi platformami

247 ICZ Copyright © 2009, Rudolf Pecinovský 247 Implementace ►Vzor je spíše obecným doporučním, které jednotlivé vazby nijak konkrétně nespecifikuje ►V jednodušších aplikacích se některé části často slučují

248 ICZ Copyright © 2009, Rudolf Pecinovský 248 Diagram tříd hry Reversi

249 Vaše jistota na trhu IT Návštěvník (Visitor)074 ►Umožňuje definovat pro skupinu tříd nové operace jejich instancí, aniž by bylo nutno jakkoliv měnit kód těchto tříd. Obsah

250 ICZ Copyright © 2009, Rudolf Pecinovský 250 Charakteristika ►Umožňuje definovat nové operace instancí, aniž by bylo nutno měnit kód jejich tříd ►Hodí se v situacích, kdy se počet tříd již nemění, ale mění se počet metod, které musí jejich instance umět ►Pro každou přidávanou metodu je třeba definovat zvláštní třídu návštěvníka

251 ICZ Copyright © 2009, Rudolf Pecinovský 251 Makroimplementace – Navštívený ►Instance třídy, která má spolupracovat s návštěvníkem, musí definovat metodu pro příjem návštěvníka ►V těle metody je jediný příkaz: předání řízení metodě návštěvníka public class Navštívený { //... public přijmi( INávštěvník návštěvník, Object param ) { návštěvník.aplikujNa( this, param ); } //... }

252 ICZ Copyright © 2009, Rudolf Pecinovský 252 Makroimplementace – návštěvník ►Návštěvník musí implementovat rozhraní, které deklaruje přetíženou verzi metody pro každou navštěvovanou třídu ►Aby překladač zvolil správnou přetíženou verzi, nesmí se navštěvované třídy spolehnout na dědění, ale každá musí definovat svoji vlastní, byť stále stejnou verzi přijímací metody ►Pro rozhraní návštěvníka je možné definovat adaptér, který může usnadnit definici návštěvníkových metod ►Adaptér může využít dědičnost a umožnit tak nedefinovat reakce pro některé typy

253 ICZ Copyright © 2009, Rudolf Pecinovský 253 Diagram tříd

254 ICZ Copyright © 2009, Rudolf Pecinovský 254 Příklad rozhraní s adaptérem public interface INávštěvník { public Object aplikujNa( AHýbací in, Object param ); public Object aplikujNa( APosuvný in, Object param ); public Object aplikujNa( Čára in, Object param ); public Object aplikujNa( Čtverec in, Object param ); public Object aplikujNa( Elipsa in, Object param ); public Object aplikujNa( Kruh in, Object param ); public Object aplikujNa( Obdélník in, Object param ); public Object aplikujNa( Obrázek in, Object param ); public Object aplikujNa( Text in, Object param ); public Object aplikujNa( Trojúhelník in, Object param ); //== VNOŘENÉ TŘÍDY ========================================== public static class Adaptér implements INávštěvník { public Object aplikujNa( APosuvný in, Object param) { throw new UnsupportedOperationException(); } public Object aplikujNa( Čára in, Object param ) { return aplikujNa((APosuvný)in, param ); } public Object aplikujNa( Text in, Object param ) { return aplikujNa((APosuvný)in, param ); } public Object aplikujNa( AHýbací in, Object param ) { return aplikujNa((APosuvný)in, param ); } public Object aplikujNa( Obrázek in, Object param ) { return aplikujNa((AHýbací)in, param ); } public Object aplikujNa( Trojúhelník in, Object param){ return aplikujNa((AHýbací)in, param ); } public Object aplikujNa( Elipsa in, Object param ) { return aplikujNa((AHýbací)in, param ); } public Object aplikujNa( Kruh in, Object param ) { return aplikujNa((Elipsa)in, param ); } public Object aplikujNa( Obdélník in, Object param ) { return aplikujNa((AHýbací)in, param ); } public Object aplikujNa( Čtverec in, Object param ) { return aplikujNa((Obdélník)in, param ); }

255 ICZ Copyright © 2009, Rudolf Pecinovský 255 Mikroimplementace – popis ►Při aplikaci návštěvníkovy metody zavoláme přijímací metodu navštíveného, tj. objektu, za nějž bude návštěvník provádět akci ►Navštívený v této metodě zavolá svoji verzi návštěvníkovy metody, která vše provede místo navštíveného, a vrátí výsledek, který navštívený předá, jako by připravil sám

256 ICZ Copyright © 2009, Rudolf Pecinovský 256 Mikroimplementace – sekvenční diagram ►Pořadí požadovaných akcí: 1. Akce A na objektu 1 2. Akce A na objektu 2 3. Akce B na objektu 1 Před vyvoláním akce je třeba získat návštěvníka, který akci provede

257 Vaše jistota na trhu IT Pamětník (Memento)075 ►Zabezpečuje uchovávání stavů objektů, aby je bylo v případě potřeby možno uvést do původního stavu. Přitom zabezpečuje, aby při uchovávání stavu nebylo narušeno ukrytí implementace. Obsah

258 ICZ Copyright © 2009, Rudolf Pecinovský 258 Charakteristika ►Ukazuje, jak je možno uchovávat informace o stavech objektů pro potřeby jejich pozdějšího opětného nastavení ►Hlavním problémem je nutnost maximálního skrytí informací o instanci, jejíž stav chceme uložit

259 ICZ Copyright © 2009, Rudolf Pecinovský 259 Implementace ►Instance uchovávající stav mohou implementovat pouhé značkovací rozhraní ►Vlastní pamětníci bývají většinou definováni jako vnitřní třídy ►Je třeba si rozmyslet, kdy raději uchovávat informace o provedených akcích a kdy výsledné pozice ►Místo celých pozic je možno uchovávat jen jejich inkrementální změny

260 Vaše jistota na trhu IT Interpret (Interpreter)076 ►Definuje reprezentaci gramatických pravidel jazyka pomocí systému tříd, a současně definuje interpret tohoto jazyka pomocí metod instancí těchto tříd. Obsah

261 ICZ Copyright © 2009, Rudolf Pecinovský 261 Charakteristika ►Ukazuje, jak je možno relativně jednoduše implementovat interpret vlastního jazyka ►Zabývá se pouze vnitřní reprezentací programu a její interpretací ►Neřeší převod textového zápisu do této reprezentace, tj. nezahrnuje lexikální a syntaktickou analýzu ►Klasický překlad: ● Lexikální analýza: najde symboly jazyka ● Syntaktická analýza: Vytvoří vnitřní reprezentaci (VR) ● Sémantická analýza: Vytvoří kód nebo VR přímo interpretuje

262 ICZ Copyright © 2009, Rudolf Pecinovský 262 Implementace ►Převádí gramatická pravidla do systému tříd ►Instance těchto tříd pak představují části vytvářeného programu ►Je velmi efektivní při implementaci jednodušších gramatik ►U složitějších gramatik je výhodnější sáhnout po klasických postupech

263 ICZ Copyright © 2009, Rudolf Pecinovský 263 Výhody ►Umožňuje snadnou realizaci i poměrně rafinovaných operací, mezi něž patří např. substituce proměnné výrazem apod. ►Přeložené programy je možné spouštět nad různými sadami hodnot jejich proměnných uložených v instanci nějakého kontextu

264 ICZ Copyright © 2009, Rudolf Pecinovský 264 Příklad 1: Regulární výraz – Gramatika ►Výraz ::= Literál | Volba | Posloupnost | Opakování | '(' Výraz ')' ►Volba ::= Výraz '|' Výraz ►Posloupnost ::= Výraz '&' Výraz ►Opakování ::= Výraz '*' ►Literál ::= 'a' | 'b' | 'c' |... { 'a' | 'b' | 'c' |... }*

265 ICZ Copyright © 2009, Rudolf Pecinovský 265 Příklad 1: Diagram tříd popsané gramatiky ►Výraz ::= Literál | Volba | Posloupnost | Opakování | '(' Výraz ')'

266 ICZ Copyright © 2009, Rudolf Pecinovský 266 Příklad 1 – diagram objektů ►Diagram objektů pro výraz: padají & (žáby | trakaře) *

267 ICZ Copyright © 2009, Rudolf Pecinovský 267 Příklad 1 – diagram objektů ►Diagram objektů pro výraz: padají & (žáby | trakaře) * ● new Posloupnost( "padají", new Opakování( new Volba( "žáby", "trakaře")

268 ICZ Copyright © 2009, Rudolf Pecinovský 268 Příklad 2: Aritmetický výraz – gramatika ►Konstanta ::= '#'číslo'#' ►Proměnná ::= Identifikátor ►Poločlen ::= Proměnná | Konstanta | '(' Výraz ')' ►Člen ::= Poločlen | '+'Poločlen | '-'Poločlen ►Součin ::= Člen | Součin '*' Člen | Součin '/' Člen ►Součet ::= Součin | Součet '+' Součin | Součet '–' Součin ►Výraz ::= Součet

269 ICZ Copyright © 2009, Rudolf Pecinovský 269 Příklad 2: Diagram tříd interpretu aritmetických výrazů Diagram tříd interpretu aritmetických výrazů

270 ICZ Copyright © 2009, Rudolf Pecinovský 270 Příklad 3: Jazyk robota – Gramatika ►Program ::= [ DefiniceProcedury | DefiniceFunkce ]... Příkaz ►DefiniceProcedury ::= $Identifikátor Příkaz ►DefiniceFunkce ::= §Identifikator. PříkazVracejícíHodnotu ►Identifikátor ::= ZobecněnéPismeno [ ZobecněnéPismeno | Číslice ]... ►ZobecněnéPísmeno ::= Písmeno | _  Komentář ::= « Text » ►Podmínka ::= ?Funkce Příkaz [ : Příkaz ]  Volání ::= !Procedura ►Opakování Příkaz...  While ::= ¤Funkce Příkaz... ►Příkaz ::= Podmínka | Opakování | While | Volání | Break | Return | { [Příkaz ]... } ►Procedura ::= IdentifikátorDefinovanéProcedury | IdentifikátorAtomickéProcedury ►IdentifikátorAtomickéProcedury ::= krok | vlevoVbok | poloz | zvedni ►Funkce ::= IdentifikátorDefinovanéFunkce | IdentifikátorAtomickéFunkce ►IdentifikátorAtomickéFunkce ::= jeZnacka | jeZed | jeRobot | jeVychod ►NastavHodnotu ::= +++ | --- | ^Funkce (  Break ::= >>>  Return ::= ###)

271 Vaše jistota na trhu IT Děkuji za pozornost Rudolf Pecinovský ICQ:

272 Vaše jistota na trhu IT ICZCopyright © 2009, Rudolf Pecinovský 272

273 ICZ Copyright © 2009, Rudolf Pecinovský 273 Pgm Používaná písma a objekty ► Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Demi) ● Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Medium) ● Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Cond) ►Příliš žluťoučký kůň úpěl ďábelské ódy (Heavy) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Franklin Gothic Book) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Comic Sans MS) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Consolas) Program Keyword Opakování Příliš žluťoučký kůň úpěl ďábelské ódy


Stáhnout ppt "Vaše jistota na trhu IT Návrhové vzory Rudolf PECINOVSKÝ"

Podobné prezentace


Reklamy Google