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

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

Rudolf PECINOVSKÝ rudolf@pecinovsky.cz Návrhové vzory Rudolf PECINOVSKÝ rudolf@pecinovsky.cz.

Podobné prezentace


Prezentace na téma: "Rudolf PECINOVSKÝ rudolf@pecinovsky.cz Návrhové vzory Rudolf PECINOVSKÝ rudolf@pecinovsky.cz."— Transkript prezentace:

1 Rudolf PECINOVSKÝ rudolf@pecinovsky.cz
Návrhové vzory Rudolf PECINOVSKÝ

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

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

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

5 00 Předehra 00 Ohlédnutí do historie 001 Quo vadis programování? 002
Základní principy OOP 003 Rozhraní 004 Zapouzdření a skrývání implementace 005 Další užitečné zásady 006

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

8 Jednoduchá tovární metoda 010
Obsah Jednoduchá tovární metoda 010 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.

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) Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

11 Příklad: AČlověk Tovární metoda může rozhodnout o skutečném typu vráceného objektu 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" ); } Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

13 Neměnné objekty (Immutable objects ) 012
Obsah Neměnné objekty (Immutable objects ) 012 Neměnný objekt je hodnotový objekt, u nějž není možno změnit jeho hodnotu.

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. 1181 Dělení na hodnotové a odkazové není terminologicky vhodné protože objektové typy dále dělíme na hodnotové a odkazové Copyright © 2009, Rudolf Pecinovský ICZ

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 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 Copyright © 2009, Rudolf Pecinovský ICZ

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ě Copyright © 2009, Rudolf Pecinovský ICZ

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#) Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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 ); //... Copyright © 2009, Rudolf Pecinovský ICZ

21 Přepravka (Crate, Transport Object) 013
Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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; } Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

26 Obsah 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.

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í Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

29 Služebník – diagramy tříd
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 Klient posílá zprávu přímo služebníku a v parametru mu současně předává instanci, kterou má obsloužit Copyright © 2009, Rudolf Pecinovský ICZ

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 ); Copyright © 2009, Rudolf Pecinovský ICZ

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ětla Copyright © 2009, Rudolf Pecinovský ICZ

32 Prázdný objekt (Null Object) 015
Obsah 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.

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 <T> Set<T> emptySet() public static final <T> List<T> emptyList() public static final <T> Map<T> emptyMap() Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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

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

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

42 Knihovní třída (Library class, Utility) 021
Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

45 Jedináček (Singleton) 022
Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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; } Copyright © 2009, Rudolf Pecinovský ICZ

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) Copyright © 2009, Rudolf Pecinovský ICZ

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

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

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

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 ) { JEDINÁČEK = new Jedináček(); } return JEDINÁČEK; Copyright © 2009, Rudolf Pecinovský ICZ

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(); Copyright © 2009, Rudolf Pecinovský ICZ

55 Výčtový typ (Enumeration) 023
Obsah 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.

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ší Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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; } Copyright © 2009, Rudolf Pecinovský ICZ

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); Deklarace hodnot (veřejných konstant) daného typu Pole hodnot 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í Copyright © 2009, Rudolf Pecinovský ICZ

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) Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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<String,Směr8> názvy = new HashMap<String,Směr8>( 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 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í Mapa pro získání instance zadaného názvu či zkratky Konstruktor ukládá všechny parametry do přepravky, aby je bylo možno vyzvednout ve statickém inicializačním bloku 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 Copyright © 2009, Rudolf Pecinovský ICZ

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 ) ); Copyright © 2009, Rudolf Pecinovský ICZ

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) Copyright © 2009, Rudolf Pecinovský ICZ

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 Diamanty public enum Operace { PLUS { public int proveď( int a, int b) { return a + b; } }, MINUS { return a - b; }; public abstract proveď( int a, int b ); //... Operace op = PLUS; int výsledek = op.proveď( x, y ); Copyright © 2009, Rudolf Pecinovský ICZ

66 Příklad 2: Člověk 1/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(); Copyright © 2009, Rudolf Pecinovský ICZ

67 Příklad 2: Člověk 2/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(); Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

69 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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

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

76 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 <Hodnota,Instance> příp. <Název,Instance> 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 Copyright © 2009, Rudolf Pecinovský ICZ

79 Obsah 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ů.

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) Copyright © 2009, Rudolf Pecinovský ICZ

81 Implementace Stav objektu je rozdělen do dvou částí Příklady
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) Vnitřním stavem je vzhled obrazce, Vnějším stavem je jeho umístění na hrací desce Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

83 03 Skrývání implementace 03
Obsah Zástupce (Proxy) 031 Příkaz (Command) 032 Iterátor (Iterator) 033 Stav (State) 034 Šablonová metoda (Template Method) 035

84 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 ); Copyright © 2009, Rudolf Pecinovský ICZ

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í(); } Copyright © 2009, Rudolf Pecinovský ICZ

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š(); } Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

99 Obsah 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.

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 Připravíme „proměnnou“ Až budeme vědě, co se má dělat, vložíme do proměnné kód Až budeme potřebovat kód provést, vytáhneme jej z proměnné a provedeme Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

103 Vyhledání položky 1/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<? super T> 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<T> lt, T klíč) Collections.binarySearch(List<T> ta, T klíč, Comparator<? super T> c) K získání komparátoru, který třídí v obráceném pořadí, slouží Collections.reverseOrder() Collections.reverseOrder(Comparator<T> cmp) Copyright © 2009, Rudolf Pecinovský ICZ

104 Třídění a vyhledání maxima/minima
K setřídění kolekce slouží metody List.sort(List<T> coll) List.sort(List<T> coll, Comparator<? super T> 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<T> coll) Collections.max(Collection<T> coll, Comparator<? super T> c) K vyhledání nejmenšího prvku v kolekci slouží metody Collections.min(Collection<T> coll) Collections.min(Collection<T> coll, Comparator<? super T> c) Copyright © 2009, Rudolf Pecinovský ICZ

105 Zdrojový kód metody max(Collection<T>)
//Deklarace typových parametrů jsou zjednodušené public static <T extends Comparable<T>> T max(Collection<T> coll) { Iterator<T> i = coll.iterator(); T candidate = i.next(); while(i.hasNext()) { T next = i.next(); if (next.compareTo(candidate) > 0) candidate = next; } return candidate; 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 Příklad převzat z knihovní třídy java.util.Collections Copyright © 2009, Rudolf Pecinovský ICZ

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

107 Příklad: Třídění nativní a modulo
public class Modulo2 implements Comparable<Modulo2> { 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<Modulo2> 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 Copyright © 2009, Rudolf Pecinovský ICZ

108 Příklad: Třídění nativní a modulo
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] public class Modulo2 implements Comparable<Modulo2> { 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<Modulo2> { public int compare( Modulo2 a, Modulo2 b) { if( a.modul != b.modul ) return (a.modul - b.modul); else return a.hodnota - b.hodnota; } Copyright © 2009, Rudolf Pecinovský ICZ

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(); } Copyright © 2009, Rudolf Pecinovský ICZ

110 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

114 Implementace Iterátor bývá v Javě implementován jako vnitřní třída
Rozhraní Iterator<E> 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 Copyright © 2009, Rudolf Pecinovský ICZ

115 interface Iterator package java.util;
public interface Iterator<E> { /** 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(); } Copyright © 2009, Rudolf Pecinovský ICZ

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( ")" ); Copyright © 2009, Rudolf Pecinovský ICZ

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á Copyright © 2009, Rudolf Pecinovský ICZ

118 Iterovatelné objekty Java 5 zavedla iterovatelné objekty – jejich třídy implementují rozhraní Iterable<E> Rozhraní požaduje implementaci jediné metody: public Iterator<E> 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 Copyright © 2009, Rudolf Pecinovský ICZ

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( ")" ); Copyright © 2009, Rudolf Pecinovský ICZ

120 Příklad: Fronta – atributy a metody
public class Fronta<E> implements Iterable<E> { private final List<E> prvky = new LinkedList<E>(); 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<E> iterator() { return new MůjIterator( this ); Copyright © 2009, Rudolf Pecinovský ICZ

121 Příklad: Fronta – vnořená třída
private class MůjIterator implements Iterator<E> { private int pořadí = 0; private Fronta<E> f; MůjIterator( Fronta<E> 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(); Protože je definována uvnitř třídy, má přístup k soukromým složkám jejích instancí Neplnohodnotná implementace – volání metody způsobí chybu Copyright © 2009, Rudolf Pecinovský ICZ

122 Příklad: Fronta – Test public static void test() {
Random rnd = new Random(); Fronta<Integer> fronta = new Fronta<Integer>(); 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.println("===== Fronta obsloužena ====="); Copyright © 2009, Rudolf Pecinovský ICZ

123 Příklad: iterátor složkou
public interface IPříkaz { public void příkaz( Object... objects ); } public class Složka implements Iterable<File> { 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<File> comparator ) {/*tělo*/} public String toString() {/*tělo*/} public Iterator<File> iterator() {return new FileIterator(filtr,comp);} private class FileIterator implements Iterator<File> { public FileIterator(FileFilter filtr, Comparator<File> 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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

125 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

129 Šablonová metoda (Template Method) 035
Obsah Š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á.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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; } Copyright © 2009, Rudolf Pecinovský ICZ

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() { } Copyright © 2009, Rudolf Pecinovský ICZ

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

135 Příklad: DieMIDlet_1 – realizace
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 Copyright © 2009, Rudolf Pecinovský ICZ

136 04 Optimalizace rozhraní 04
Obsah Fasáda (Facade) 041 Adaptér (Adapter) 042 Strom (Composite) 043

137 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

141 Obsah 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é.

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 Copyright © 2009, Rudolf Pecinovský ICZ

143 Charakteristika Účel Nasazení
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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

145 Metoda s definovatelnou implementací používající vzor Šablonová metoda
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 ) { public void setPozice( Pozice pozice ) { setPozice( pozice.x, pozice.y ); Adaptér je definován jako třída vnořená do rozhraní, na něž bude své potomky adaptovat Metody, o jejichž implementaci se uživatel může rozhodnout podle potřeby Metoda s definovatelnou implementací používající vzor Šablonová metoda Copyright © 2009, Rudolf Pecinovský ICZ

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 ) { Adaptér je definován jako vnořená třída rozhraní, na něž bude své potomky adaptovat Metoda s definovatelnou implementací používající vzor Šablonová metoda Metody, o jejichž implementaci se uživatel může rozhodnout podle potřeby Copyright © 2009, Rudolf Pecinovský ICZ

147 Adaptovaný objekt jako atribut 1/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; } Copyright © 2009, Rudolf Pecinovský ICZ

148 Adaptovaný objekt jako atribut 2/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ý); Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

150 Obsah 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ů.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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: Copyright © 2009, Rudolf Pecinovský ICZ

156 Tovární metoda (Factory method) 051
Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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); Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

165 Obsah 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.

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ě Copyright © 2009, Rudolf Pecinovský ICZ

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ší Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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; Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

173 Kdy co Obecně bývá výhodnější Nemusí tomu tak ale být vždy
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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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 ); Copyright © 2009, Rudolf Pecinovský ICZ

180 Obsah 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ů.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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ří Copyright © 2009, Rudolf Pecinovský ICZ

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ů Copyright © 2009, Rudolf Pecinovský ICZ

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 ); } Copyright © 2009, Rudolf Pecinovský ICZ

187 Sázecí program – diagram tříd
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 Výkonný objekt Výkonný objekt Výkonný objekt Řídící objekt Ukázka Copyright © 2009, Rudolf Pecinovský ICZ

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

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(); Copyright © 2009, Rudolf Pecinovský ICZ

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) { Copyright © 2009, Rudolf Pecinovský ICZ

191 Abstraktní továrna (Abstract factory) 054
Obsah 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ů.

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) Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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

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

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ů Copyright © 2009, Rudolf Pecinovský ICZ

199 06 Ochrana před rozrůstáním 06
Obsah Dekorátor (Decorator) 061 Řetěz odpovědnosti (Chain of responsibility) 062 Pozorovatel (Observer) 063 Prostředník (Mediator) 064

200 Dekorátor (Decorator) 061
Obsah 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í.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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, …) Copyright © 2009, Rudolf Pecinovský ICZ

203 Implementace 1/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 Copyright © 2009, Rudolf Pecinovský ICZ

204 Implementace 2/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ů Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 ); Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

210 + / – Výhody Nevý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 Copyright © 2009, Rudolf Pecinovský ICZ

211 Řetěz odpovědnosti 062 (Chain of responsibility)
Obsah Ř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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Strom Copyright © 2009, Rudolf Pecinovský ICZ

216 Pozorovatel (Observer), Posluchač (Listener) 063
Obsah 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í.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

223 Prostředník (Mediator) 064
Obsah 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.

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é Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Pozorovatel Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

231 Obsah 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ě.

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čů Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

235 Po aplikaci vzoru Most Třída CPU implementuje rozhraní ICPU deklarující tři metody: RozměrKláves getRozměr() List<String> 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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

237 Testování sady programů
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 Copyright © 2009, Rudolf Pecinovský ICZ

238 Obsah 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.

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í Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

244 MVC (Model – View – Controller) 073
Obsah 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ů.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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í Copyright © 2009, Rudolf Pecinovský ICZ

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

249 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 ); } Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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 ) { public Object aplikujNa( AHýbací in, Object param ) { public Object aplikujNa( Obrázek in, Object param ) { return aplikujNa((AHýbací)in, param ); public Object aplikujNa( Trojúhelník in, Object param){ public Object aplikujNa( Elipsa in, Object param ) { public Object aplikujNa( Kruh in, Object param ) { return aplikujNa((Elipsa)in, param ); public Object aplikujNa( Obdélník in, Object param ) { public Object aplikujNa( Čtverec in, Object param ) { return aplikujNa((Obdélník)in, param ); Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

257 Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

260 Interpret (Interpreter) 076
Obsah 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.

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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' | ... }* Copyright © 2009, Rudolf Pecinovský ICZ

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

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

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") Copyright © 2009, Rudolf Pecinovský ICZ

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 Copyright © 2009, Rudolf Pecinovský ICZ

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

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 | _ l Komentář ::= « Text » Podmínka ::= ?Funkce Příkaz [ : Příkaz ] l Volání ::= !Procedura Opakování Příkaz... l 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 (l Break ::= >>> l Return ::= ###) Copyright © 2009, Rudolf Pecinovský ICZ

271 Děkuji za pozornost Rudolf Pecinovský ICQ:

272 Copyright © 2009, Rudolf Pecinovský
ICZ

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) Příliš žluťoučký kůň úpěl ďábelské ódy Příliš žluťoučký kůň úpěl ďábelské ódy Opakování Program Keyword Příliš žluťoučký kůň úpěl ďábelské ódy Copyright © 2009, Rudolf Pecinovský ICZ


Stáhnout ppt "Rudolf PECINOVSKÝ rudolf@pecinovsky.cz Návrhové vzory Rudolf PECINOVSKÝ rudolf@pecinovsky.cz."

Podobné prezentace


Reklamy Google