APLIKACE NÁVRHOVÝCH VZORŮ



Podobné dokumenty
SW_11. Strategie - Strategy Šablona metoda template

SW_12. Vzor Příkaz - Command Vzor Návštěvník - Visitor

1. Dědičnost a polymorfismus

typová konverze typová inference

1. Programování proti rozhraní

Úvod do programovacích jazyků (Java)

20. Projekt Domácí mediotéka

Výčtový typ strana 67

Bridge. Známý jako. Účel. Použitelnost. Handle/Body

Při studiu tohoto bloku se předpokládá, že student je zvládá základy programování v jazyce Java s využitím vývojového prostředí NetBeans.

Obsah přednášky 9. Skrývání informací. Skrývání informací. Zapouzdření. Skrývání informací. Základy programování (IZAPR, IZKPR) Přednáška 9

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

KTE / ZPE Informační technologie

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

Návrhové vzory. Jakub Klemsa, Jan Legerský. 30. října Objektově orientované programování.

TÉMATICKÝ OKRUH Softwarové inženýrství

TÉMATICKÝ OKRUH Softwarové inženýrství

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

Abstraktní třída a rozhraní

Návrhové vzory Design Patterns

Semin aˇr Java N avrhov e vzory Radek Ko ˇc ı Fakulta informaˇcn ıch technologi ı VUT Duben 2009 Radek Koˇc ı Semin aˇr Java N avrhov e vzory 1/ 25

Java - výjimky. private void vstup() throws IOException {... }

7. přednáška - třídy, objekty třídy objekty atributy tříd metody tříd

OOPR_05. Případové studie

Generické programování

Návrhové vzory OMO, LS 2014/2015

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

Semin aˇr Java N avrhov e vzory Radek Ko ˇc ı Fakulta informaˇcn ıch technologi ı VUT Duben 2008 Radek Koˇc ı Semin aˇr Java N avrhov e vzory 1/ 24

Využití OOP v praxi -- Knihovna PHP -- Interval.cz

ČÁST 1. Zahřívací kolo. Co je a k čemu je návrhový vzor 33

Teoretické minimum z PJV

Projekty pro výuku programování v jazyce Java

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

boolean hasnext() Object next() void remove() Kolekce

Základy objektové orientace I. Únor 2010

2. Modelovací jazyk UML 2.1 Struktura UML Diagram tříd Asociace OCL. 3. Smalltalk 3.1 Jazyk Pojmenování

Vyřešené teoretické otázky do OOP ( )

Úvod do programování - Java. Cvičení č.4

8 Třídy, objekty, metody, předávání argumentů metod

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Třídy, polymorfismus. A0B36PR2-Programování 2 Fakulta elektrotechnická České vysoké učení technické

Typický prvek kolekce pro české řazení

Dynamicky vázané metody. Pozdní vazba, virtuální metody

11 Diagram tříd, asociace, dědičnost, abstraktní třídy

Algoritmizace a programování

Abstraktní datové typy: zásobník

Dalším příkladem může být například výstup dat na různá zařízení, souborů, grafických rozhraní, sítě atd.

PŘETĚŽOVÁNÍ OPERÁTORŮ

Seminář Java IV p.1/38

Java - řazení objektů

3. Třídy. Základní pojmy objektového programování. Třídy

Obsah. Zpracoval:

Principy objektově orientovaného programování

SW_10. Dekorátor - Decorator Stav - State

PROMĚNNÉ, KONSTANTY A DATOVÉ TYPY TEORIE DATUM VYTVOŘENÍ: KLÍČOVÁ AKTIVITA: 02 PROGRAMOVÁNÍ 2. ROČNÍK (PRG2) HODINOVÁ DOTACE: 1

11. Dědičnost. Dědičnost strana 103

ROZDÍL MEZI VZTAHEM EXTEND A INCLUDE V USE CASE DIAGRAMECH

Java GUI události. Událostmi řízené programování. Zpracování = obsluha událostí

Pokročilé typové úlohy a scénáře 2006 UOMO 71

PREPROCESOR POKRAČOVÁNÍ

7.5 Diagram tříd pokročilé techniky

IB111 Programování a algoritmizace. Objektově orientované programování (OOP)

1. Téma 12 - Textové soubory a výjimky

Úvod Třídy Rozhraní Pole Konec. Programování v C# Hodnotové datové typy, řídící struktury. Petr Vaněček 1 / 39

7 Formátovaný výstup, třídy, objekty, pole, chyby v programech

Programování II. Modularita 2017/18

9. Polymorfismus a rozhraní

17. Projekt Trojúhelníky

Objektové programování

Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám.

Aplikace s grafickým uživatelským rozhraním

15. Projekt Kalkulačka

Algoritmizace a programování

9. přednáška - třídy, objekty

PB161 Programování v jazyce C++ Přednáška 7

PB161 Programování v jazyce C++ Přednáška 7

Dědičnost (inheritance)

IRAE 07/08 Přednáška č. 1

Klíčová slova: OOP, konstruktor, destruktor, třída, objekt, atribut, metoda

OMO. 4 - Creational design patterns A. Singleton Simple Factory Factory Method Abstract Factory Prototype Builder IoC

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

RMI - Distribuované objekty v Javě

Programování v C++ 3, 3. cvičení

3. Je defenzivní programování technikou skrývání implementace? Vyberte jednu z nabízených možností: Pravda Nepravda

Java a XML. 10/26/09 1/7 Java a XML

Vývoj informačních systémů. Architektura, návrh Vzory: Doménová logika

Třídy. Instance. Pokud tento program spustíme, vypíše následující. car1 má barvu Red. car2 má barvu Red. car1 má barvu Blue.

RMI Remote Method Invocation

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

TŘÍDY POKRAČOVÁNÍ. Události pokračování. Příklad. public delegate void ZmenaSouradnicEventHandler (object sender, EventArgs e);

Student s Life. Návrhová dokumentace (Design) Lukáš Barák, Jakub Ječmínek, Jaroslav Brchel, Jiří Zmeškal

Webové služby a XML. Obsah přednášky. Co jsou to webové služby. Co jsou to webové služby. Webové služby a XML

Úvod do programovacích jazyků (Java)

IRAE 07/08 Přednáška č. 7. Začátek (head)

Programování II. Třídy a objekty (objektová orientovanost) 2018/19

UJO Framework. revoluční architektura beans. verze

7.5 Diagram tříd pokročilé techniky

Class loader. každá třída (java.lang.class) obsahuje referenci na svůj class loader. Implementace class loaderu

Observer. Klasifikace. Alias. Smysl. Potřeba sledování změn objektu a notifikace. Obdoba systému událostí (C#, Java) vlastními prostředky

7. Dynamické datové struktury

Transkript:

APLIKACE NÁVRHOVÝCH VZORŮ URČENO PRO VZDĚLÁVÁNÍ V AKREDITOVANÝCH STUDIJNÍCH PROGRAMECH FRANTIŠEK HUŇKA ČÍSLO OPERAČNÍHO PROGRAMU: CZ.1.07 NÁZEV OPERAČNÍHO PROGRAMU: VZDĚLÁVÁNÍ PRO KONKURENCESCHOPNOST OPATŘENÍ: 7.2 ČÍSLO OBLASTI PODPORY: 7.2.2 INOVACE VÝUKY INFORMATICKÝCH PŘEDMĚTŮ VE STUDIJNÍCH PROGRAMECH OSTRAVSKÉ UNIVERZITY REGISTRAČNÍ ČÍSLO PROJEKTU: CZ.1.07/2.2.00/28.0245 OSTRAVA 2012

Tento projekt je spolufinancován Evropským sociálním fondem a státním rozpočtem České republiky Recenzent: RNDr. Jaroslav Žáček, Ph.D. Název: Aplikace návrhových vzorů Autor: doc. Ing. František Huňka, CSc. Vydání: první, 2012 Počet stran: 154 Jazyková korektura nebyla provedena, za jazykovou stránku odpovídá autor. doc. Ing. František Huňka, CSc. Ostravská univerzita v Ostravě

OBSAH Úvod pro práci s textem pro distanční studium... 4 1 Úvod do problematiky... 5 2 Vzor Strategie a Šablona... 9 2.1 Strategie... 9 2.2 Šablona... 13 3 Vzor Model-View- Controller (Observer)... 22 4 Vzory Dekorátor a Visitor... 34 4.1 Dekorátor... 34 4.2 Visitor... 39 5 Vzor Továrna (Factory)... 43 5.1 Jednotuchá továrna (Simple Factory)... 43 5.2 Tovární metoda (Factory Method)... 47 5.3 Abstraktní továrna (Abstract Factory)... 50 6 Vzor Příkaz (Command)... 55 7 Vzory Adaptér a Fasáda (Adapter, Facada )... 66 7.1 Vzor Adaptér... 66 7.2 Vzor Fasáda... 72 8 Vzory Iterátor a Skladba (Iterator, Composite)... 79 8.1 Vzor Iterátor... 79 8.2 Vzor Skladba... 91 9 Vzor Stav (State)... 97 10 Vzor Proxy... 105 10.1 Vzdálené proxy... 109 10.2 Dynamické proxy... 114 11 Vzory architektury... 121 11.1 Vzor vrstvy (Layers)... 121 11.2 Vzor roury a filtry (Pipes and Filters)... 127 12 Návrhový vzor Broker... 133 13 Adaptivní systémy... 141 13.1 Microkernel... 141 13.2 Reflexe (Reflection)... 149 Korespondenční úkoly... 154 Literatura... 155 3

Úvod pro práci s textem pro distanční studium Cíl předmětu Seznámit studenty s praktickým využitím návrhových vzorů. Popis a vysvětlení jednotlivých návrhových vzorů je ještě doplněno názornými příklady v jazyce Java. Tento aspekt výuky je velmi zásadní a umožňuje lépe pochopit vlastní podstatu návrhových vzorů. Po prostudování textu budete znát: Tento učební text je určen studentům informatiky pro předmět Aplikace návrhových vzorů. Cílem textu je seznámit studenty se zavedenými a opětovně použitelnými vzory v objektově orientovaném přístupu. Studium jednotlivých vzorů také pomůže nejen prohloubit chápání principů OOP, ale také při jejich praktickém uplatnění v navrhovaných aplikacích. Záverečné kapitoly textu se věnují vzorům architektury. V textu jsou dodržena následující pravidla: - je specifikován cíl kapitoly (tedy co by měl student po jejím absolvování umět, znát, pochopit), - výklad učiva, - důležité pojmy, - doplňující otázky a úkoly k textu. Úkoly Na konci učebního textu jsou uvedeny tři příklady, které během semestru zpracujete a zašlete ke kontrole vyučujícímu. Zadané příklady odpovídají postupně probíranému učivu. Podrobné informace obdržíte na úvodním tutoriálu. Pokud máte jakékoliv věcné nebo formální připomínky k textu, kontaktujte autora (frantisek.hunka@osu.cz). Inovace předloženého textu Učební text prošel celkovou úpravou. Kompletně byly přepracovány nebo nově doplněny následující návrhové vzory: Jednoduchá továrna, Tovární metoda, Abstraktní továrna, Adaptér, Fasáda, Iterátor, Skladba, Stav, Vzdálené proxy, Dynamické proxy. Z původního textu byly vypuštěny návrhové vzory Forwarder-Receiver a Client- Dispatcher-Server. 4

1 Úvod do problematiky V této kapitole se dozvíte: co jsou návrhové vzory a jak se používají, jaké jsou tři základní aspekty každého vzoru, jak se návrhové vzory dokumentují. Po jejím prostudování budete schopni: lépe rozumět důvodům, proč se používají návrhové vzory a jaké může být jejich potenciální využití při tvorbě aplikací. Klíčová slova této kapitoly: návrhový vzor, kontext, problém, řešení Základní pojmy Jednou z možností tvorby objektově orientovaných aplikací je využití tzv. návrhových vzorů resp. vzorů pro návrh angl. Design Patterns. Klíčovým pojmem pro vysvětlení vzorů pro návrh je znovupoužitelnost. Znovupoužitelnost v oblasti tvorby software znamenala úspěch především v objektově orientovaných jazycích tam je označována jako dědičnost a také v oblasti business objects. Business objects jsou části software, které je možno po malém přizpůsobení použít v typizované oblasti (např. účetnictví). Obě tato použití mají společnou vlastnost znovupoužitelnost je v nich použita na úrovni implementace. Vzory pro návrh vycházejí z práce zkušeného návrháře ten totiž nezačíná svoji práci od nuly, ale pokud se nějaký způsob řešení osvědčil, má tendenci používat jej v dalších projektech, čímž jej zdokonaluje. Způsob řešení zde neznamená použití určité části kódu, ale znovupoužití znalostí nabytých v průběhu návrhu. Znovupoužitelnost je tedy možno chápat ve více úrovních. Pokud mluvíme o dědičnosti a business objektech, jde o znovupoužitelnost na úrovni implementační, pokud mluvíme o návrhových vzorech, jde o znovupoužitelnost v oblasti návrhu. Co jsou vzory pro návrh. Návrhové vzory by měly napomoci účinnému sdílení a znovupoužitelnosti znalostí na vyšší úrovni mezi lidmi zabývajícími se 5

projektováním a návrhem v určitém oboru. Návrhové vzory mají svůj původ v architektuře, kde byly použity pro popis opakujících se námětů při navrhování architektonických celků. Odtud se rozšířily nejen do oblasti objektově orientovaného návrhu, ale i do dalších oborů. Vzorem pro návrh (v softwarové oblasti) může být libovolná znalost, která vznikla při návrhu informačního systému abstrakcí od specifických konkrétních podmínek. Je zřejmé, že taková znalost musí proto, aby mohla být uložena a znovupoužita dostat konkrétní fyzickou podobu. Forma zápisu vzoru pro návrh není pevně dána, ale je závislá na tom, čeho se zkušenost, kterou chceme vyjádřit návrhovým vzorem, týká. Pokud jde např. o zobecnění vztahů mezi objekty a definici rolí, je možné použít objektový diagram, pokud jde o zobecněné chování, může se jednat o sekvenční diagram atd. Z praktické zkušenosti vyplývá, že každý model použitý při návrhu potřebuje slovní komentář, který bude přesně specifikovat použité prvky a vazby v modelu a umožní nezúčastněnému čtenáři pochopení problému. Pro objasnění účelu, podmínek použití, struktury atd. se hodí např. níže uvedený popis. Atributy potřebné pro popis vzoru Jméno vzoru resp. další jména, pod kterými je vzor znám. Kontext situace, ve které se může vzor uplatnit. Problém je problém, který vzor řeší včetně diskuse požadavků. Řešení základní princip řešení. Struktura detailní specifikace struktury vzoru a jejich aspektů. Dynamika je popsána scénářem chování vzoru během jeho vykonávání. Implementace hlavní body implementace vzoru. Varianty řešení. Známé použití vzoru. Výhody navrženého řešení. Slabá místa řešení. V poslední době se návrhové vzory přímo spojují se softwarovou architekturou. Rozsah návrhových vzorů může pokrývat nejvyšší úroveň tzv. vzory architektury přes návrhové vzory až po vzory na nejnižší úrovni tzv. idiomy. Často se vyskytuje v této souvislosti pojem vzorově orientovaná softwarová architektura (pattern-oriented software architecture). Návrhové vzory mohou být klasifikovány buď podle účelu na vzory pro tvorbu objektů, vzory pro řešení struktury, vzory řešící chování, nebo podle kritéria granularity na vzory architektury, vzory pro návrh a idiomy. Charakteristika vzoru Vzor můžeme výstižně charakterizovat jako vztah (relace) mezi daným kontextem, problém a řešením. 6

Každý prvek na světě, každý vzor je vztahem mezi jistým kontextem, daným systémem požadavků (sil), které nastávají opakovaně v tomto kontextu a danou prostorovou konfigurací, která dovoluje těmto silám vyřešit své působení. Kontext: situace, která způsobuje problém. Problém: opakující se problém v daném kontextu. Řešení: prověřené a ověřené řešení problému. Kontext: Kontext rozšiřuje stručný popis o popis situace, ve které problém vzniká. Kontext vzoru může být zcela všeobecný, např. vytvoření software s rozhraním pro člověka. Na druhé straně kontext může spolu vázat specifické vzory jako např. implementace mechanismu propagace změny ve vzoru Model View Controller. Specifikace správného kontextu je pro vzor obtížná. Prakticky je nemožné určit všechny situace, jak všeobecné, tak specifické, ve kterých může být vzor použit. Daleko pragmatičtější je mít v seznamu všechny známé situace, kde problém, který je řešen daným vzorem, se může vyskytnout. To samozřejmě negarantuje, že pokryjeme všechny situace, ve kterých může být vzor relevantní, ale alespoň to dá cenné vodítko. Problém: Tato část schématu popisu vzoru popisuje problém, který vzniká opakovaně v daném kontextu. Začíná s obecnou specifikací problému, zaměřujíce se na to nejpodstatnější co musí návrhový vzor řešit. Například vzor Model-View-Controller je zaměřen na problémy způsobené změnou uživatelského rozhraní. Tento problém specifikuje dva protichůdné požadavky: uživatelské rozhraní by mělo být snadno modifikovatelné; funkcionální jádro programového řešení by nemělo být ovlivněno touto modifikací. Požadavky obecně pomáhají prodiskutovat problém z různých úhlů pohledu a pomáhají porozumět detailům. Mohou působit stejným směrem, nebo proti sobě. Dva protichůdné požadavky jsou např. rozšiřitelnost systému versus minimalizace velikosti jeho jádra. Když chcete, aby váš systém byl rozšiřitelný, máte tendenci použít abstraktní nadtřídu. Když ale chcete minimalizovat rozsah kódu, nemůžete si dovolit luxus, jako jsou abstraktní nadtřídy. Nejdůležitější jsou samozřejmě klíčové požadavky řešící problém. Řešení: Řešení je část popisu vzoru, která ukazuje, jak vyřešit opakující se problém, nebo lépe jak vyrovnat působící požadavky (síly) spojené s tímto problémem. V softwarové architektuře má takové řešení dva aspekty. 7

Za prvé, každý vzor určuje (specifikuje) jistou strukturu (prostorovou konfiguraci prvků). Tato struktura má vazbu na statické aspekty řešení a jako každá jiná softwarová architektura se skládá z komponent a vztahů mezi nimi. Uvnitř této struktury slouží komponenty jako stavební bloky a každá komponenta má svoji funkci (zodpovědnost). Vztahy mezi komponentami určují jejich umístění. Za druhé, každý vzor je určen chováním za běhu (při použití). Toto chování má vazbu na dynamické aspekty řešení, tedy jak dílčí části vzoru spolupracují, jak je mezi nimi organizovaná práce, jak komunikují mezi sebou. Je důležité zdůraznit, že řešení nemusí nevyhnutně vyřešit všechny požadavky spojené s daným problémem. Může se soustředit na některé z nich a zbytek požadavků ů nechat neřešen. Musíme mít na mysli, že požadavky působí protichůdně, což mnohdy komplikuje jejich úplné vyřešení. Návrhový vzor se využívá při znovupoužitelnosti na úrovni znalostí. Základní charakteristikou každého vzoru je kontext, problém a řešení. Situace, kterou je třeba řešit je vždy v nějakém kontextu. Požadavky, které se vyskytují, bývají protichůdné. Řešení obsahuje vytvoření rovnováhy mezi různými požadavky. V řešení nemusí být uspokojeny všechny požadavky. Kontrolní otázky 1. Jak lze charakterizovat návrhový vzor? 2. V čem se liší znovupoužitelnost z hlediska objektově orientovaného přístupu od znovupoužitelnosti návrhových vzorů? Shrnutí obsahu kapitoly Cílem úvodní kapitoly je popsat problematiku, které se učební text bude věnovat a tím studenty motivovat ke studiu učebního textu. 8

2 Vzor Strategie a Šablona (Strategy, Template) V této kapitole se dozvíte: jak je možné využít polymorfismus v jednotlivých návrhových vzorech, jak je možné dodeklarovat generické metody, jak se dají využívat tzv. operace orientované na vzory. Po jejím prostudování budete schopni: lépe chápat a využívat polymorfismus, využít získané vědomosti při aplikacích návrhových vzorů. Klíčová slova této kapitoly: polymorfismus, strategie, šablona. 2.1 Vzor Strategie Kontext: V různých oblastech můžeme narazit na problém, že danou operaci můžeme řešit několika možnými algoritmy (strategiemi). Navíc je požadováno, aby konkrétní algoritmus (strategie) byl vybrán až v době běhu programu. Konkrétně se může jednat o vyhledání minima, a to podle algoritmů: LeastSquare, NewtonsMethod, Bisection a ConjugateGradient. Problém: Je třeba, aby aplikace dovedla pracovat s různými algoritmy, řešící daný problém. Řešení pomocí přepínače e není vhodné, protože není dostatečně přizpůsobitelné změnám (flexibilní). Řešení: Záměrem vzoru Strategie je zapouzdřit alternativní přístupy (nebo strategie, čtyři metody uvedené v kontextu) v samostatných třídách, kde každá implementuje danou operaci (strategii). Za běhu programu je pak možné spočítat minimum různými metodami (strategiemi) a podle toho se rozhodnout. 9

Obr. 2.1 Diagram tříd UML zobrazující strukturu návrhového vzoru Strategie Třída MiniSolver obsahuje jednak odkaz prostřednictvím datového atributu strategy na rozhraní FindMinima. Dále metody minima(), která realizuje konkrétní algoritmus a metoda changealgoritmus(), která mění algoritmus výpočtu viz zdrojový výpis programu. public interface FindMinima { // Line is a sequence of points: double[] algorithm(double[] line); Rozhraní FindMinima pak implementuje řada různých metod, které mají svůj algoritmus pro výpočet minima. Pro snadné pochopení vzoru algoritmy (strategie) nemají těla metod, ale pouze vypisují řadu reálných čísel jako výsledek algoritmu. // Různé strategies výpočtu minima: public class LeastSquares implements FindMinima { @Override public double[] algorithm(double[] line) { return new double[] { 1.1, 2.2 ; public class NewtonsMethod implements FindMinima { @Override public double[] algorithm(double[] line) { return new double[] { 3.3, 4.4 ; 10

public class Bisection implements FindMinima { @Override public double[] algorithm(double[] line) { return new double[] { 5.5, 6.6 ; public class ConjugateGradient implements FindMinima { @Override public double[] algorithm(double[] line) { return new double[] { 3.3, 4.4 ; Třída MinimaSolver deklaruje datový atribut typu rozhraní FindMinima strategy, do kterého je pak uložen konkrétní algoritmus podle kterého má probíhat výpočet. Konstruktor této třídy zabezpečí, aby do datového atributu byla přiřazena konkrétní hodnota. Metoda minima() pak provádí konkrétní výpočet podle zadaného algoritmu (strategie). Další metoda changealgorithm() dovoluje změnit algoritmus (strategii) za jiný. public class MinimaSolver { private FindMinima strategy; public MinimaSolver(FindMinima strat) { strategy = strat; double[] minima(double[] line) { return strategy.algorithm(line); void changealgorithm(findminima newalgorithm) { strategy = newalgorithm; Třída ArrayX je pomocná třída, která je využita pro převod pole reálných čísel na řetězec, který se pak snadno vytiskne. Vlastní převodní metoda je třídní (statická), a proto nemá ani třída z vnějšku přístupný konstruktor. Pro převod je využita třída StringBuffer. public class ArrayX { private ArrayX() { public static String tostring(double[] a) { StringBuffer result = new StringBuffer("["); for(int i = 0; i < a.length; i++) { result.append(a[i]); if(i < a.length - 1) result.append(", "); result.append("]"); return result.tostring(); 11

Třída StrategyPattern pak demonstruje využití vzoru. Proměnná solver je instancí třídy MinimaSolver a při jejím vytvoření se jako parametr předává konkrétní algoritmus (strategie) výpočtu. Pole line obsahuje řadu reálných čísel, sloužící jako fiktivní vstup do algoritmu výpočtu. Výraz solner.minima(line) vrací výsledek (fiktivní) použitého algoritmu. Metoda solver.changealgorithm() mění algoritmus (strategii) výpočtu. public class StrategyPattern { public static void main(string args[]) { MinimaSolver solver = new MinimaSolver(new LeastSquares()); double[] line = { 1.0, 2.0, 1.0, 2.0, -1.0, 3.0, 4.0, 5.0, 4.0 ; System.out.println( ArrayX.toString(solver.minima(line))); solver.changealgorithm(new Bisection()); System.out.println( ArrayX.toString(solver.minima(line))); Návrhový vzor Strategy zjednodušuje složitou strukturu výpočtu tím, že zavádí pro každou strategii samostatnou třídu. Každá takováto třída zapouzdřuje jednu strategii (algoritmus výpočtu) a vytváří jednodušší kód. Typický klient má k dispozici výběr strategie. Je k tomu využito polymorfismu. 12

2.2 Šablona Template Method Problém: Při definování metody bychom rádi definovali pouze základní obrysy (návrh) algoritmu a ponechali možnost rozdílné implementace jistých kroků. Kontext: Definice metod, které mají společný obecný základ, ale liší se v implementaci konkrétních kroků. Řešení: Zavedení vzoru Šablona (Template method), jejímž cílem je implementovat daný algoritmus v metodě, přičemž odkládá definování některých kroků algoritmu tak, že je jiné třídy mohou redefinovat (dodefinovat). Nejdříve uvedeme příklad objasňující vzor šablona na příkladu přípravy pravy kávy a čaje. Dále pak následuje klasický příklad třídění. Příprava kávy a čaje zápis v kódu public class Coffee { final void preparerecipe() { boilwater(); // vaření vody brew(); // spaření pourincup(); //nalévání do šálku addsugarandmilk(); //přidání cukru a mléka public void boilwater() { System.out.println("Vaření vody"); public void void brew() { System.out.println("Překapání kávy přes filtr"); public void pourincup() { System.out.println("Nalití kávy do šálku"); public void addsugarandmilk() { System.out.println("Přidání cukru a mléka"); Metoda preparerecipe() obsahuje celý postup přípravy kávy. Dílčí metody jsou uvedeny následně. Metoda preparerecipe() pro třídu Tea je podobná, má však dvě různé metody. 13

public class Tea { final void preparerecipe() { boilwater(); steepteabag(); // vyluhování čajového sáčku pourincup(); addlemon(); // přidání citronu... Z kódu vidíme, že dvě metody jsou stejné jako ve třídě Coffee, ale dvě jsou odlišné. Obr. 2.2 Příprava kávy a čaje diagram tříd UML Na obr. 2.2 je znázorněn další postup při řešení. Abstraktní třída CoffeineBeverage (kofejnový nápoj) má dvě podtřídy, z nichž každá předeklarovává metodu preparerecipe(). Toto řešení dále upravíme tak, že zavedeme nové metody brew() a addcondiments() do metody preparerecipe(). To pak znamená, že tato metoda nemusí být předeklarovaná v podtřídách. public abstract class CaffeineBeverage { final void preparerecipe() { boilwater(); brew(); // metoda předeklarovaná v podtřídách pourincup(); addcondiments(); // metoda předeklarovaná v // podtřídách abstract void brew(); // příprava nápoje abstract void addcondiments(); // přídání dochucovadel void boilwater() { System.out.println("Varici voda"); 14

void pourincup() { System.out.println("Nalevani do salku"); Implementace dvou uvedených metod v podtřídě Coffee. Podobně je tomu i ve třídě Tea. public class Coffee extends CaffeineBeverage { public void brew() { System.out.println("Prekapani kavy přes filtr"); public void addcondiments() { System.out.println("Pridani cukru a mleka"); Jak vidíme z předchozího postupu, návrhový vzor šablona definuje kroky algoritmu a dovoluje podtřídám implementovat některé z jeho kroků. Detailnější definice návrhového vzoru šablona je následující: Vzor šablona definuje kostru algoritmu v metodě, která odsouvá některé ze svých kroků do podtříd. Metoda šablona dovoluje podtřídám předefinovat jisté kroky algoritmu, beze změn struktury algoritmu. Dále je uvedena struktura této metody v programovém kódu: public abstract class AbstractClass { final void templatemethod() { // metoda předeklarovaná v podtřídě primitiveoperation1(); // metoda předeklarovaná v podtřídě primitiveoperation2(); concreteoperation(); abstract void primitiveoperation1(); abstract void primitiveoperation2(); void concreteoperation() { // implementace metody void hook() { Metoda templatemethod() je finální, což znamená, že nemůže být předeklarovaná v podtřídách. Ta vlastně tvoří kostru algoritmu. Metody primitivnioperace1,2() jsou abstraktní a musí být předeklarované v podtřídách. Metoda hook() (háček, skoba) je 15

konkrétní metoda a nemusí dělat nic. Pomáhá při nastavování defaultních hodnot. Viz následující kód: public abstract class CaffeineBeverageWithHook { void preparerecipe() { boilwater(); brew(); pourincup(); // zákazník chce přísady (cukr..) if (customerwantscondiments()) { addcondiments(); abstract void brew(); abstract void addcondiments(); void boilwater() { System.out.println("Boiling water"); void pourincup() { System.out.println("Pouring into cup"); // metoda hook(), podtřída ho může ale // nemusí předeklarovat boolean customerwantscondiments() { return true; Následující třída je podtřídou třídy CaffeineBeberageWithHook. public class CoffeeWithHook extends CaffeineBeverageWithHook { public void brew() { System.out.println("Dripping Coffee through filter"); public void addcondiments() { System.out.println("Adding Sugar and Milk"); // podtřída předeklaruje metodu nadtřídy public boolean customerwantscondiments() { String answer = getuserinput(); if (answer.tolowercase().startswith("y")) { return true; else { return false; 16

private String getuserinput() { String answer = null; System.out.print("Would you like milk and sugar with your coffee (y/n)? "); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); try { answer = in.readline(); catch (IOException ioe) { System.err.println("IO error trying to read your answer"); if (answer == null) { return "no"; return answer; Jak je vidět z podtřídy, ta má možnosti metodu hook() předeklarovat a ptá se zákazníka, zda chce nebo nechce přísady do zvoleného nápoje. Následující programový kód ukazuje jednoduché použití popisovaného příkladu. public class BeverageTestDrive { public static void main(string[] args) { Coffee coffee = new Coffee(); System.out.println("\nMaking coffee..."); coffee.preparerecipe(); CoffeeWithHook coffeehook = new CoffeeWithHook(); System.out.println("\nMaking coffee..."); coffeehook.preparerecipe(); Třída CaffeineBeverage je naše vysoko úrovňová komponenta. Ta má kontrolu nad algoritmem, který je uveden v metodě preparerecipe() a volá podtřídy, pouze když jsou potřebné pro implementaci metody. Dalším příkladem je klasický příklad třídění. Třídící algoritmy se liší v přístupu a v rychlosti, ale každý třídící algoritmus spočívá na základních krocích porovnání dvou položek nebo atributů. Třídění je dávný příklad vzoru šablona. Je to postup, který nám dovoluje měnit jeden kritický krok a tím je porovnání dvou objektů, tak, aby se algoritmus dal použít vícekrát pro různé kolekce objektů. 17

Třídy Array a Collection v Javě poskytují metodu sort(), která je deklarovaná jako třídní (statická) a pole (array), které se má setřídit, se jí zadává jako argument. Dále metoda někdy požaduje volitelný Comparator (rozhraní). Collection c = Collection.sort(array) Naproti tomu třída ArrayList poskytuje instanční metodu sort(), která třídí příjemce této zprávy. ArrayList al = arraylist.sort() Oba přístupy jsou ale závislé na rozhraních Comparable a Comparator. Rozdíl mezi nimi je pouze v tom, že rozhraní Comparable očekává oba porovnávané objekty jako argumenty, zatímco Comparator očekává pouze jeden argument (porovnávaný objekt), druhý objekt představuje Comparator sám. Metoda sort() ve třídách Array a Collection dovoluje využívat ke třídění instance rozhraní Comparator. Pokud ji neuvedeme, metoda sort() bude využívat metodu compareto() rozhraní Comparable. Většina primitivních typů včetně třídy String implementuje rozhraní Comparable. Třídění (řazení) primitivních typů probíhá podle implicitně implementovaného rozhraní Comparable v těchto typech (třídách). Objektový typ - obsahující více typů (objektových, primitivních) - nejdříve nutno implementovat rozhraní Comparable, aby bylo jasné, podle kterých datových atributů objektového typu se bude třídit (porovnávat). Rozhraní Comparable obsahuje následující metodu: public interface Comparable { public int compareto(t o); Metoda compareto() porovnává přijímající objekt (příjemce zprávy) se specifikovaným objektem jako argumentem metody a vrací: 0 obě hodnoty jsou stejné 1 příjemce je větší, než objekt specifikovaný jako argument (kladné číslo) -1 příjemce je menší, než objekt specifikovaný jako argument (záporné číslo) public class OsobaJmeno implements Comparable<OsobaJmeno> { private String jmeno, prijmeni; public OsobaJmeno(String jmeno, String prijmeni){ this.jmeno = jmeno; this.prijmeni = prijmeni; 18

public String getjmeno(){ return jmeno; public String getprijmeni(){ return prijmeni; public boolean equals(object o){ if(!(o instanceof OsobaJmeno)) return false; OsobaJmeno oj = (OsobaJmeno) o; return oj.getjmeno().equals(jmeno) && oj.getprijmeni().equals(prijmeni); public String tostring(){ return "Jmeno: "+jmeno+" prijmeni: "+prijmeni; public int compareto(osobajmeno oj){ int porovnani = prijmeni.compareto(oj.prijmeni); return (porovnani!= 0? porovnani : jmeno.compareto(oj.jmeno)); public class OsobaJmenoTest { public static void main(string[] args) { OsobaJmeno o1, o2, o3, o4; o1 = new OsobaJmeno("Jan", "Zelenka"); o2 = new OsobaJmeno("Jan","Zehnal"); o3 = new OsobaJmeno("Jan","Zehnal"); o4 = new OsobaJmeno("Adam","Sedlacek"); System.out.println("o1 + o2 "+o1.compareto(o2)); System.out.println("o2 + o3 "+o2.compareto(o3)); System.out.println("o1 + o4 "+o1.compareto(o4)); System.out.println("o4 + o3 "+o4.compareto(o3)); Využití třídění import java.util.*; public class OsobaJmenoSort { public static void main(string args[]){ OsobaJmeno polejmen[] = { new OsobaJmeno("Jiri","Maly"), new OsobaJmeno("Odlrich","Maly"), new OsobaJmeno("Adam","Maly"), new OsobaJmeno("Alena","Mala"), new OsobaJmeno("Anna","Maliskova") ; List<OsobaJmeno> jmena = Arrays.asList(poleJmen); Collections.sort(jmena); System.out.println(jmena); 19

Další porovnávání objektů je možné dělat s využitím rozhraní Comparator, které deklaruje dvě metody: public interface Comparator<t> { int compare(t o1, T o2); boolean equals(object o); Třída TimeComparator implementuje rozhraní Comparator k porovnání dvou objektů třídy Time import java.util.comparator; public class TimeComparator implements Comparator< Time2 > { public int compare( Time2 time1, Time2 time2 ) { // porovná hodiny int hourcompare = time1.gethour() - time2.gethour(); // nejdříve test hodin - hour if ( hourcompare!= 0 ) return hourcompare; // porovná minuty int minutecompare = time1.getminute() - time2.getminute(); // potom test minut if ( minutecompare!= 0 ) return minutecompare; // porovná vteřiny int secondcompare = time1.getsecond() - time2.getsecond(); return secondcompare; // vrací výsledek porovnání // Třídění seznamu s použitím tříd Comparator a // TimeComparator. import java.util.list; import java.util.arraylist; import java.util.collections; public class Sort3 { public void printelements() { // vytvoření seznamu List< Time2 > list = new ArrayList< Time2 >(); list.add( new Time2( 6, 24, 34 ) ); list.add( new Time2( 18, 14, 58 ) ); list.add( new Time2( 6, 05, 34 ) ); list.add( new Time2( 12, 14, 58 ) ); 20

list.add( new Time2( 6, 24, 22 ) ); // výstup prvků seznamu System.out.printf( "Unsorted array elements:\n%s\n", list ); // třídění s využitím comparator Collections.sort( list, new TimeComparator() ); // výstup prvků seznamu System.out.printf( "Sorted list elements:\n%s\n", list ); // konec metody printelements() public static void main( String args[] ) { Sort3 sort3 = new Sort3(); sort3.printelements(); Záměrem vzoru šablona je definovat algoritmus v metodě a nechat při tom některé kroky abstraktní, nebo definovat rozhraní, které může být implementováno rozdílně v různých třídách. Další třídy pak mohou doplňovat chybějící kroky, nebo implementovat rozhraní různě podle svých potřeb. 21

3 Vzor Model-View-Controller (Observer) V této kapitole se dozvíte: jak je možné sledování změn objektu tak, že mezi objektem a objekty které ho sledují, není přímá vazba, jak je realizován mechanismus šíření změn, v jakých jiných oblastech se tento vzor vyskytuje. Po jejím jím prostudování budete schopni: navrhnout a inmplementovat aplikace využívající tento vzor, využívat třídy a rozhraní, které poskytuje platforma Javy. Klíčová slova kapitoly: model-view-controller, observer Tento vzor dělí interaktivní aplikaci na tři komponenty. Model obsahuje jádro funkcionality a data, Views (pohledy) zobrazují informace pro uživatele a Controllers zpracovávají uživatelský vstup. Views a Controllers spolu zahrnují uživatelské rozhraní. Mechanismus šíření změn zabezpečuje konzistentnost mezi uživatelským rozhraním a modelem. Kontext Interaktivní aplikace s pružným rozhraním člověk-počítač. Problém Uživatelské rozhraní je náchylné v požadavcích na změny. Když rozšíříte íte funkcionalitu aplikace, musíte modifikovat přístup k menu o nové funkce. Je-li uživatelské rozhraní těsně propojeno s funkcionálním jádrem aplikace, je budování systému s uvedenou flexibilitou drahé a náchylné k chybám. Tento postup ale vyústí v potřebu vývoje a údržby několika podstatně odlišných programových systémů, jeden pro každé uživatelské rozhraní. Následující požadavky ovlivňují řešení: 22

Stejné informace jsou prezentovány odlišně v různých oknech, např. sloupcový graf, koláčový graf, číselná tabulka. Zobrazování a chování aplikace musí odrážet okamžitou manipulaci s daty. Změny v uživatelském rozhraní by měly být snadné a možné i za běhu programu. Podpora různých standardů a portování uživatelského rozhraní by neměla ovlivňovat kód jádra aplikace. Řešení Model-View-Controller (MVC) byl poprvé uveden v objektově orientovaném programovém prostředí Smalltalk-80. MVC dělí interaktivní aplikaci na tři oblasti: model (výpočet), vstupy, výstupy. Komponenta model zapouzdřuje základní data a funkcionalitu. Model je nezávislý na specifikacích vstupního a výstupního chování aplikace. Komponenta View (pohled - výstup) zobrazuje uživateli informace. View dostává data od modelu. Na model může existovat několik pohledů. Každá komponenta View je asociovaná s komponentou controller (řízení - vstup). Controllers dostávají vstup obyčejně jako události, které jsou způsobeny pohybem myši, stisknutím tlačítka myši, nebo stisknutím klávesy na klávesnici. Tyto události jsou transformovány na požadavky služeb pro model nebo view. Uživatel má interakci se systémem výhradně prostřednictvím komponent controller. Separace komponenty model od komponent view a controller umožňuje násobné pohledy na stejný model. Pokud uživatel změní model prostřednictvím komponenty controller jedné komponenty view, všechny ostatní komponenty view závislé na těchto datech se také změní. Komponenta model proto uvědomuje všechny komponenty view, zda-li se jejich data změnila. Komponenty view na druhou stranu obnovují data z komponenty model a aktualizují zobrazované informace. Mechanismus propagace změn je také popsán ve vzoru Publisher-Subscriber. Struktura Komponenta model obsahuje funkcionální jádro aplikace. Zapouzdřuje data a exportuje procedury, které provádějí specifické zpracování aplikace. Komponenty controller volají tyto procedury místo uživatele. Komponenta model také poskytuje funkce pro přístup k jeho datům, které používají komponenty view, aby získaly a zobrazily data. Mechanismus šíření změn udržuje seznam závislých komponent uvnitř modelu. Všechny komponenty view a také vybrané komponenty 23