SW_10. Dekorátor - Decorator Stav - State



Podobné dokumenty
APNVZ_10. Dekorátor - Decorator Stav - State

KTE / ZPE Informační technologie

Výčtový typ strana 67

Generické programování

Úvod do programovacích jazyků (Java)

Soubor jako posloupnost bytů

Výchozí a statické metody rozhraní. Tomáš Pitner, upravil Marek Šabo

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

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

Abstraktní datové typy: zásobník

RMI Remote Method Invocation

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

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

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

Java - řazení objektů

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

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

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

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

20. Projekt Domácí mediotéka

typová konverze typová inference

State. Známý jako. Účel. Použitelnost. Stav, Object for States. umožňuje objektu měnit svoje chování v závislosti na stavu objekt mění svou třídu

Dědičnost (inheritance)

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

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

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

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

Abstraktní třída a rozhraní

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

8. přednáška: Soubory a proudy

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

Úvod do programovacích jazyků (Java)

Datové struktury. alg12 1

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

Typický prvek kolekce pro české řazení

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

Návrhové vzory OMO, LS 2014/2015

Semin aˇr Java V yjimky Radek Ko ˇc ı Fakulta informaˇcn ıch technologi ı VUT Unor 2008 Radek Koˇc ı Semin aˇr Java V yjimky 1/ 25

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

1. Programování proti rozhraní

Statické proměnné a metody. Tomáš Pitner, upravil Marek Šabo

Algoritmizace a programování

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

Principy objektově orientovaného programování

Jazyk C# (seminář 3)

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

IRAE 07/08 Přednáška č. 2. atr1 atr2. atr1 atr2 -33

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

1. Dědičnost a polymorfismus

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

Výjimky. v C# a Javě

PREPROCESOR POKRAČOVÁNÍ

Návrhové vzory Design Patterns

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

Vytváření a použití knihoven tříd

Z. Kotala, P. Toman: Java ( Obsah )

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

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

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

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

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

Java Výjimky Java, zimní semestr

Teoretické minimum z PJV

RMI - Distribuované objekty v Javě

Algoritmizace a programování

4. ZÁKLADNÍ POJMY Z OBJEKTOVĚ ORIENTOVANÉHO PROGRAMOVÁNÍ

Datové struktury. Obsah přednášky: Definice pojmů. Abstraktní datové typy a jejich implementace. Algoritmizace (Y36ALG), Šumperk - 12.

6. PRÁCE S DATOVÝMI PROUDY

Textové soubory. alg9 1

Práce se soubory v Javě

Objektově orientované programování v PHP 5. Martin Klíma

Distribuované systémy a výpočty

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

Tabulka symbolů. Vazba (binding) Vazba - příklad. Deklarace a definice. Miroslav Beneš Dušan Kolář

OOPR_05. Případové studie

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

Počítačové laboratoře bez tajemství aneb naučme se učit algoritmizaci a programování s využitím robotů CZ.1.07/1.3.12/

Dědění, polymorfismus

Příklad : String txt1 = new String( Ahoj vsichni! ); //vytvoří instanci třídy String a přiřadí ji vnitřní hodnotu Ahoj vsichni!

Základy objektové orientace I. Únor 2010

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

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

Návrh softwarových systém. Návrh softwarových systémů

Objektově orientované programování

Programování v Javě I. Leden 2008

NIO. Aplikační programování v Javě (BI-APJ) - 12 Ing. Jiří Daněček Katedra softwarového inženýrství Fakulta informačních technologií ČVUT Praha

Dědičnost. seskupování tříd do hierarchie. potomek získá všechny vlastnosti a metody. provádí se pomocí dvojtečky za názvem třídy.

Pokud zadání nerozumíte nebo se vám zdá nejednoznačné, zeptejte se. Pište čitelně, nečitelná řešení nebudeme uznávat.

Programování II. Návrh programu II

Základní datové struktury

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

Objektové programování

NPRG031 Programování II 1 / :25:46

NMIN201 Objektově orientované programování 1 / :36:09

17. Projekt Trojúhelníky

Programování v Javě I. Únor 2009

UJO Framework. revoluční architektura beans. verze

Regulární výrazy. Vzory

5 Rekurze a zásobník. Rekurzivní volání metody

Abstract Factory úvod

Transkript:

SW_10 Dekorátor - Decorator Stav - State 1

Úvod Dekorátor Naučíte se jak zkrášlovat (decorate) vaše třídy za běhu programu s využitím skládání objektů. Tímto způsobem budete schopni dát vašim objektům novou funkčnost bez přidávání jakéhokoli kódu do základních tříd. 2

Kontext: Úvod Dekorátor Malé změny chování objektu za běhu programu. Problém: Jak využít skládání pro dynamické změny chování objektu. 3

Řešení: Úvod Dekorátor Návrhový vzor Dekorátor, který dovoluje skládat nové varianty operace za běhu programu. 4

Příklad Kavárna rychle se rozvíjející obchod. Rychle rostoucí nabídka nápojů různě kombinovaných. Prvotní struktura tříd: 5

Příklad K vaší kávě si můžete objednat řadu přísad: vařené mléko, soju, mochu a ještě to završit se smetanou. Kavárna si účtuje zvlášť za každou položku, co si zákazník zvolí. To také potřebují zabudovat do svého systému výpočtu ceny. Jedna z možností je mít jednu třídu Nápoj a vše ostatní jako podtřídy této jedné nadtřídy. 6

Příklad Uvedené řešení bude působit problémy v údržbě systému. Co se stane, když se zvýší cena mléka? Co se stane, když se přidá nová karamelová příchuť? 7

Příklad Potřebujeme všechny ty třídy? Nestačily by pouze instanční proměnné? Boolovská hodnota pro každou přísadu. Cena se spočítá podle počtu přísad. description milk soy mocha whip Beverage getdescription() cost() hasmilk() setmilk() hassoy() setsoy() hasmocha() setmocha() haswhip() setwhip() // other methods 8

Příklad Cena v nadtřídě bude počítat ceny v podtřídách. Každá z podtříd spočítá hodnotu přísad a zavolá metodu pro výpočet ceny z nadtřídy. HouseBlend description milk soy mocha whip getdescription() cost() hasmilk() setmilk() hassoy() setsoy() hasmocha() setmocha() haswhip() setwhip() Beverage // other methods DarkRoast Decaf Espresso cost() cost() cost() cost() 9

Příklad Neřeší úplně problémy rozšiřování do budoucna. Měnící se ceny přísad nás nutí měnit kód. Nové přísady nás nutí přidat nové metody a změnit metodu cost() v nadtřídě. Pro nový nápoj nemusí být všechny z existujících přísad vhodné. Co když chce zákazník double mocha? 10

Princip otevření-zavření Open Closed principle Třídy by měly být otevřené pro rozšíření, ale uzavřené pro modifikaci. Našim cílem je dovolit třídám, aby byly snadno rozšiřitelné pro začlenění nového chování bez modifikace existujícího kódu. Čeho tím dosáhneme? Návrhy, které jsou odolné změnám a dostatečně flexibilní pro přijetí nové funkcionality, aby vyhověly měnícím se požadavkům. 11

Otevření pro změny, uzavření pro modifikace? Zní to protichůdně. Existují OOP techniky, umožňující rozšíření beze změny existujícího kódu. přidání dalších pozorovatelů Observer Ač se to může zdát protichůdné, existují techniky, kterém dovolují rozšíření kódu bez přímé modifikace. Opatrnost při výběru částí kódu, které potřebují rozšíření. Aplikace principu je všude zbytečná. 12

Konstrukce nápojové objednávky s Dekorátorem 1. DarkRoast dědí ze třídy Beverage metodu cost(), která počítá cenu nápoje. 2. Mocha dekorátor, ale také nápoj (podtřída Beverage) 3. Whip - dekorátor 13

Konstrukce nápojové objednávky s Dekorátorem 1. Volání metody cost() dekorátoru Whip. 2. Whip volá cost() na Mocha. 3. Mocha volá cost() na DarkRoast. 4. DarkRoast vrací 99 centů. 5. Mocha přidává 20 centů ($1.19). 6. Whip přidává 10 centů - ($1.29). 14

Dekorátor Dekorátory mají stejnou nadtřídu jako objekty, které dekorují. Je možné použít jeden nebo více dekorátorů, které obalí (wrap) daný objekt. To, že dekorátor a objekt mají stejnou nadtřídu umožňuje nechat kolovat dekorátor místo dekorovaného objektu. Dekorátor přidává své vlastní chování buď před, nebo po delegování objektu, který dekoruje, aby udělal zbytek práce. 15

Dekorátor Objekty mohou být dekorovány kdykoli, můžeme dekorovat objekty dynamicky za běhu, tolika dekorátory, kolik se nám zlíbí. 16

Vzor Dekorátor Vzor Dekorátor přidává dodatečnou funkčnost (chování) objektu dynamicky. Dekorátory poskytují flexibilní alternativu k dědičnosti pro rozšíření funkcionality. 17

Vzor Dekorátor ConcreteComponent je objekt, jehož funkcionalitu rozšiřujeme. Component methoda() methodb() // other methods Každá component může být použita samostatně, nebo obalena dekorátorem. ConcreteComponent methoda() methodb() // other methods Decorator methoda() methodb() // other methods Dekorátory implementují stejné rozhraní abstraktní třídy, jako komponenty, které dekorují. ConcreteDecoratorA má datový atribut pro odkaz na objekt, který dekoruje. ConcreteDecoratorA Component wrappedobj methoda() methodb() newbehavior() ConcreteDecoratorB Component wrappedobj() Object newstate methoda() methodb() Dekorátor může rozšířit stav komponenty. // other method // other methods 18

Konkrétní příklad 19

public abstract class Beverage { String description = "Unknown Beverage"; Poznámky public String getdescription() { return description; public abstract double cost();

public abstract class CondimentDecorator extends Beverage { public abstract String getdescription(); Poznámky 21

public class Espresso extends Beverage { Poznámky public Espresso() { description = "Espresso"; public double cost() { return 1.99; 22

public class HouseBlend extends Beverage { public HouseBlend() { description = "House Blend Coffee"; Poznámky public double cost() { return.89; 23

public class Mocha extends CondimentDecorator { Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; Poznámky Implementace konkrétního dekorátoru public String getdescription() { return beverage.getdescription() + ", Mocha"; public double cost() { return.20 + beverage.cost(); 24

public class StarbuzzCoffee { Poznámky public static void main(string args[]) { Beverage beverage = new Espresso(); System.out.println(beverage.getDescription() + " $" + beverage.cost()); Beverage beverage2 = new DarkRoast(); beverage2 = new Mocha(beverage2); beverage2 = new Mocha(beverage2); beverage2 = new Whip(beverage2); System.out.println(beverage2.getDescription() + " $" + beverage2.cost()); Beverage beverage3 = new HouseBlend(); beverage3 = new Soy(beverage3); beverage3 = new Mocha(beverage3); beverage3 = new Whip(beverage3); System.out.println(beverage3.getDescription() + " $" + beverage3.cost()); Espresso $1.99 Dark Roast Coffee, Mocha, Mocha, Whip $1.49 House Blend Coffee, Soy, Mocha, Whip $1.34 25

Reálné dekorátory Java I/O Java I/O třídy využívají dekorátory. Dva dekorátory a jeden objekt. 26

import java.io.*; public class LowerCaseInputStream extends FilterInputStream { public LowerCaseInputStream(InputStream in) { super(in); Poznámky FileInputStream je abstraktní dekorátor pro pšechny InputStreamy. public int read() throws IOException { int c = super.read(); return (c == -1? c : Character.toLowerCase((char)c)); public int read(byte[] b, int offset, int len) throws IOException { int result = super.read(b, offset, len); for (int i = offset; i < offset+result; i++) { b[i] = (byte)character.tolowercase((char)b[i]); return result; Potřebujeme dvě metody read(). Jednu pro byty a druhou pro pole bytů. 27

import java.io.*; Poznámky public class InputTest { public static void main(string[] args) throws IOException { int c; try { InputStream in = new LowerCaseInputStream( new BufferedInputStream( new FileInputStream("test.txt"))); while((c = in.read()) >= 0) { System.out.print((char)c); in.close(); catch (IOException e) { e.printstacktrace(); 28

Shrnutí - Dekorátor Vzor Dekorátor můžeme použít všude tam, kde by řešení rozšíření funkcionality děděním přinášelo problémy se vznikem kombinací výsledných řešení, to je problémy se statickou neměnnou vazbou. Příklady využití uvedeného vzoru můžeme nalézt v javovské knihovně pro práci se streamy. Tam můžeme využívat vkládání instancí do sebe. 29

Shrnutí - Dekorátor Vzor Dekorátor poskytuje flexibilní návrh v případech, kdy potřebujeme kombinovat různé implementace operací za běhu programu. 30

Kontext: Vzor Stav - State Stav objektu je dán kombinací aktuálních hodnot jeho datových atributů. Hodnoty těchto atributů měníme pomocí metod set(). Při zaslání zprávy set() objektu, se přiřadí nějaká hodnota příslušnému atributu objektu. Tím se změnil jeho stav. Objekty obyčejně mění své vlastní stavy, při vykonání jejich metod. 31

Problém: Stav V některých případech však jednoduchá implementace tohoto principu pomocí if nebo switch příkazů může vést k velmi nepřehledným konstrukcím a jejich obtížné údržbě. 32

Schematické zobrazení Stavový diagram činnost prodejního automatu se žvýkačkami. 33

public class GumballMachine { Poznámky final static int SOLD_OUT = 0; final static int NO_QUARTER = 1; final static int HAS_QUARTER = 2; final static int SOLD = 3; int state = SOLD_OUT; int count = 0; public GumballMachine(int count) { this.count = count; if (count > 0) { state = NO_QUARTER; 34

public void insertquarter() { if (state == HAS_QUARTER) { System.out.println("You can't insert another quarter"); else if (state == NO_QUARTER) { state = HAS_QUARTER; System.out.println("You inserted a quarter"); else if (state == SOLD_OUT) { System.out.println("You can't insert a quarter, the machine is sold out"); else if (state == SOLD) { System.out.println("Please wait, we're already giving you a gumball"); Poznámky public void ejectquarter() { if (state == HAS_QUARTER) { System.out.println("Quarter returned"); state = NO_QUARTER; else if (state == NO_QUARTER) { System.out.println("You haven't inserted a quarter"); else if (state == SOLD) { System.out.println("Sorry, you already turned the crank"); else if (state == SOLD_OUT) { System.out.println("You can't eject, you haven't inserted a quarter yet"); 35

public void turncrank() { if (state == SOLD) { System.out.println("Turning twice doesn't get you another gumball!"); else if (state == NO_QUARTER) { System.out.println("You turned but there's no quarter"); else if (state == SOLD_OUT) { System.out.println("You turned, but there are no gumballs"); else if (state == HAS_QUARTER) { System.out.println("You turned..."); state = SOLD; dispense(); Poznámky 36

public void dispense() { if (state == SOLD) { System.out.println("A gumball comes rolling out the slot"); count = count - 1; if (count == 0) { System.out.println("Oops, out of gumballs!"); state = SOLD_OUT; else { state = NO_QUARTER; else if (state == NO_QUARTER) { System.out.println("You need to pay first"); else if (state == SOLD_OUT) { System.out.println("No gumball dispensed"); else if (state == HAS_QUARTER) { System.out.println("No gumball dispensed"); Poznámky 37

public void refill(int numgumballs) { this.count = numgumballs; state = NO_QUARTER; Poznámky public String tostring() { StringBuffer result = new StringBuffer(); result.append("\nmighty Gumball, Inc."); result.append("\njava-enabled Standing Gumball Model #2004\n"); result.append("inventory: " + count + " gumball"); if (count!= 1) { result.append("s"); result.append("\nmachine is "); if (state == SOLD_OUT) { result.append("sold out"); else if (state == NO_QUARTER) { result.append("waiting for quarter"); else if (state == HAS_QUARTER) { result.append("waiting for turn of crank"); else if (state == SOLD) { result.append("delivering a gumball"); result.append("\n"); return result.tostring(); 38

public class GumballMachineTestDrive { public static void main(string[] args) { GumballMachine gumballmachine = new GumballMachine(5); Poznámky Zkouška System.out.println(gumballMachine); gumballmachine.insertquarter(); gumballmachine.turncrank(); System.out.println(gumballMachine); gumballmachine.insertquarter(); gumballmachine.ejectquarter(); gumballmachine.turncrank(); System.out.println(gumballMachine); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.ejectquarter(); System.out.println(gumballMachine); 39

Zhodnocení postupu Tento kód neodpovídá principu Open Closed (Otevřený pro rozšíření, uzavřený pro modifikace). Přechody stavů nejsou explicitní; jsou uloženy někde uvnitř podmínkových příkazů. Další rozšiřování bude způsobovat chyby v kódu. 40

Nový návrh Přepracovat zapouzdřené stavové objekty do vlastních tříd a delegovat aktuální stav, když akce nastane. Postup: 1. Definovat rozhraní State, které obsahuje metodu pro každou akci Gumball Machine. 2. Implementovat rozhraní State pro každý definovaný stav. Tyto třídy budou zodpovědné za chování prodejního automatu, když je v odpovídajícím stavu. 41

Nový návrh 3. Zbavit se všeho podmínkového kódu a místo něho delegovat činnosti na třídy stavů. 42

Definování rozhraní a tříd Každý stav mapujeme přímo do třídy. 4 stavy = 4 třídy 43

Popis stavů NoQuarterState jde na stav HasQuarterState. Říká zákazníkovi, že nevložil minci. HasQuarterState jde na stav SoldState. SoldState říká zákazníkovi ať počká, že dostane žvýkačku. Vydá žvýkačku, zkontroluje jejich stav if > 0, jde na stav NoQuarterState, jinak jde na stav SoldOutState. SoldOutState říká zákazníkovi, že nemá žvýkačky. 44

public class NoQuarterState implements State { GumballMachine gumballmachine; Poznámky public NoQuarterState(GumballMachine gumballmachine) { this.gumballmachine = gumballmachine; Datový atribut pro odkaz na gumballmachine. public void insertquarter() { System.out.println("You inserted a quarter"); gumballmachine.setstate(gumballmachine.gethasquarterstate()); public void ejectquarter() { System.out.println("You haven't inserted a quarter"); public void turncrank() { System.out.println("You turned, but there's no quarter"); public void dispense() { System.out.println("You need to pay first"); public String tostring() { return "waiting for quarter";

public class GumballMachine { Poznámky State soldoutstate; State noquarterstate; State hasquarterstate; State soldstate; State state = soldoutstate; int count = 0; public GumballMachine(int numbergumballs) { soldoutstate = new SoldOutState(this); noquarterstate = new NoQuarterState(this); hasquarterstate = new HasQuarterState(this); soldstate = new SoldState(this); this.count = numbergumballs; if (numbergumballs > 0) { state = noquarterstate;

public void insertquarter() { state.insertquarter(); Poznámky public void ejectquarter() { state.ejectquarter(); public void turncrank() { state.turncrank(); state.dispense(); void setstate(state state) { this.state = state; void releaseball() { System.out.println("A gumball comes rolling out the slot..."); if (count!= 0) { count = count - 1; int getcount() { return count;

void refill(int count) { this.count = count; state = noquarterstate; Poznámky public State getstate() { return state; public State getsoldoutstate() { return soldoutstate; public State getnoquarterstate() { return noquarterstate; public State gethasquarterstate() { return hasquarterstate; public State getsoldstate() { return soldstate;

public String tostring() { StringBuffer result = new StringBuffer(); result.append("\nmighty Gumball, Inc."); result.append("\njava-enabled Standing Gumball Model #2004"); result.append("\ninventory: " + count + " gumball"); if (count!= 1) { result.append("s"); result.append("\n"); result.append("machine is " + state + "\n"); return result.tostring(); Poznámky

public class HasQuarterState implements State { GumballMachine gumballmachine; Poznámky public HasQuarterState(GumballMachine gumballmachine) { this.gumballmachine = gumballmachine; public void insertquarter() { System.out.println("You can't insert another quarter"); public void ejectquarter() { System.out.println("Quarter returned"); gumballmachine.setstate(gumballmachine.getnoquarterstate()); public void turncrank() { System.out.println("You turned..."); gumballmachine.setstate(gumballmachine.getsoldstate()); public void dispense() { System.out.println("No gumball dispensed"); public String tostring() { return "waiting for turn of crank";

ublic class SoldState implements State { Poznámky GumballMachine gumballmachine; public SoldState(GumballMachine gumballmachine) { this.gumballmachine = gumballmachine; public void insertquarter() { System.out.println("Please wait, we're already giving you a gumball"); public void ejectquarter() { System.out.println("Sorry, you already turned the crank"); public void turncrank() { System.out.println("Turning twice doesn't get you another gumball!"); public void dispense() { gumballmachine.releaseball(); if (gumballmachine.getcount() > 0) { gumballmachine.setstate(gumballmachine.getnoquarterstate()); else { System.out.println("Oops, out of gumballs!"); gumballmachine.setstate(gumballmachine.getsoldoutstate());

public String tostring() { return "dispensing a gumball"; Poznámky

Definice vzoru Stav - State Vzor Stav dovoluje objektu měnit své chování, když se změní interní stavy. Zdá se, že objekt změnil svoji třídu. Context request() handle() State ConcreteStateA ConcreteStateB state.handle() handle() handle() 53

public class WinnerState implements State { GumballMachine gumballmachine; public WinnerState(GumballMachine gumballmachine) { this.gumballmachine = gumballmachine; Poznámky Rozšíření vzoru public void insertquarter() { System.out.println("Please wait, we're already giving you a Gumball"); public void ejectquarter() { System.out.println("Please wait, we're already giving you a Gumball"); public void turncrank() { System.out.println("Turning again doesn't get you another gumball!");

public void dispense() { System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter"); gumballmachine.releaseball(); if (gumballmachine.getcount() == 0) { gumballmachine.setstate(gumballmachine.getsoldoutstate()); else { gumballmachine.releaseball(); if (gumballmachine.getcount() > 0) { gumballmachine.setstate(gumballmachine.getnoquarterstate()); else { System.out.println("Oops, out of gumballs!"); gumballmachine.setstate(gumballmachine.getsoldoutstate()); Poznámky public String tostring() { return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";

public class HasQuarterState implements State { Random randomwinner = new Random(System.currentTimeMillis()); GumballMachine gumballmachine; Poznámky public HasQuarterState(GumballMachine gumballmachine) { this.gumballmachine = gumballmachine; public void insertquarter() { System.out.println("You can't insert another quarter"); public void ejectquarter() { System.out.println("Quarter returned"); gumballmachine.setstate(gumballmachine.getnoquarterstate()); public void turncrank() { System.out.println("You turned..."); int winner = randomwinner.nextint(10); if ((winner == 0) && (gumballmachine.getcount() > 1)) { gumballmachine.setstate(gumballmachine.getwinnerstate()); else { gumballmachine.setstate(gumballmachine.getsoldstate());

public void dispense() { System.out.println("No gumball dispensed"); Poznámky public String tostring() { return "waiting for turn of crank";

public class GumballMachineTestDrive { Poznámky public static void main(string[] args) { GumballMachine gumballmachine = new GumballMachine(10); System.out.println(gumballMachine); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.turncrank(); System.out.println(gumballMachine); gumballmachine.insertquarter(); gumballmachine.turncrank(); gumballmachine.insertquarter(); gumballmachine.turncrank(); System.out.println(gumballMachine);

Shrnutí Stav zapouzdřuje chování, které se mění a používá delegování k rozhodnutí, které chování použít. Návrhový vzor State využívá ker své činnosti polymorfismu. Mezi vlastní třídou a jednotlivými stavy, reprezentovanými také třídami zavedeme buď rozhraní, nebo abstraktní třídu. Vlastní třídy dílčích stavů jsou pak buď podtřídami abstraktní třídy, nebo implementují metody rozhraní. 59

Shrnutí Výhodou tohoto vzoru je snadná manipulace se stavy ve smyslu jejich modifikace, tedy přidávání dalších stavů nebo jejich rušení (odebírání). Úpravy jsou přehledné a snadno proveditelné. 60