Návrhové vzory Design Patterns



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

OOPR_05. Případové studie

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

Objektově orientované programování 1 XOBO1. Autor: Doc. Ing. František Huňka, CSc.

PREPROCESOR POKRAČOVÁNÍ

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

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

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

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

20. Projekt Domácí mediotéka

Programování v Javě I. Leden 2008

Principy objektově orientovaného programování

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

Typický prvek kolekce pro české řazení

Generické programování

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

KTE / ZPE Informační technologie

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

Výčtový typ strana 67

Návrhové vzory OMO, LS 2014/2015

, Brno Připravil: David Procházka Návrhové vzory

Abstraktní datové typy: zásobník

Infrastruktura UML. Modelování struktury v UML. Superstruktura UML. Notace objektů. Diagramy objektů

Teoretické minimum z PJV

Jazyk C# (seminář 6)

1. Programování proti rozhraní

Úvod do programovacích jazyků (Java)

APNVZ_01. Návrhové vzory Design Patterns

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

Objektově orientované programování

typová konverze typová inference

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

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

Přehled probírané látky

Abstraktní třída a rozhraní

RMI Remote Method Invocation

Základy objektové orientace I. Únor 2010

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

Kolekce ArrayList. Deklarace proměnných. Import. Vytvoření prázdné kolekce. napsal Pajclín

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

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

Java - řazení objektů

Stromy. Příklady. Rekurzivní datové struktury. Základní pojmy

OOPR_05. Případové studie

Datové struktury. alg12 1

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

Deklarace a vytváření

návrhový vzor Singleton.

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

Základy jazyka C# Obsah přednášky. Architektura.NET Historie Vlastnosti jazyka C# Datové typy Příkazy Prostory jmen Třídy, rozhraní

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

Struktura třídy, operátory, jednoduché algoritmy, junit. Programování II 2. cvičení Alena Buchalcevová

Distribuované systémy a výpočty

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

Seminář Java IV p.1/38

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

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

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

Jazyk C++ II. Šablony a implementace

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

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

Základní pojmy. Matice(řádky, sloupce) Matice(4,6) sloupce

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

Dědičnost (inheritance)

Seminář Java II p.1/43

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

Semin aˇr Java X Radek Koˇc ı Fakulta informaˇcn ıch technologi ı VUT Duben 2011 Radek Koˇc ı Semin aˇr Java N avrhov e vzory, Z asady...

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

1. Dědičnost a polymorfismus

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.

Čipové karty Lekařská informatika

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

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

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

Hiearchical MVC (Model-view-controller) vs. PAC (Presentation-abstraction-control)

III/2 Inovace a zkvalitnění výuky prostřednictvím ICT

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

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

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

Úvod do programování v jazyce Java

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

7 Jazyk UML (Unified Modeling Language)

7 Jazyk UML (Unified Modeling Language)

Mělká a hluboká kopie

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

Třídy a objekty -příklady

Pokročilé programování v jazyce C pro chemiky (C3220) Pokročilá témata jazyka C++

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

Modelování řízené případy užití

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.

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 I 2018/19

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

Java Výjimky Java, zimní semestr

NA CO SI DÁT POZOR V JAVASCRIPTU? Angular.cz

Enterprise Java (BI-EJA) Technologie programování v jazyku Java (X36TJV)

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

Java a Caché IV: Manipulace s objekty

Jazyk C# (seminář 5)

knihovna programátora

Transkript:

Návrhové vzory Design Patterns doc. Ing. František Huňka, CSc. Ostravská univerzita PřF 1

Definice vzoru Každý vzor popisuje problém, který nastává opakovaně v našem prostředí, a potom popisuje podstatu řešení tohoto problému takovým způsobem, že můžete použít řešení milionkrát bez toho, že byste dělali stejnou věc dvakrát. Christopher Alexander 2

Světlo z obou stran každého pokoje Když mají lidé na výběr, vždy tíhnou k takovým pokojům, do kterých přichází přirozené světlo alespoň ze dvou stran. Při projektování domu, je nejlepší umístit každý pokoj tak, aby měl vnější prostor alespoň ze dvou stran, s dostatkem oken, které by zachycovaly přirozené světlo více než z jednoho směru. 3

Literatura Gamma E., Helm R.: Degign Patterns. Addison -Wesley 1995 (český překlad Návrh programů pomocí vzorů. Grada 2003) 4

Základní literatura Pecinovský R.: Návrhové vzory. Computer Press 2007 Bruce Eckel: Thinking in Patterns. www.bruceeckel.com Buchmann F.: Pattern-Oriented Software Architecture A System of Patterns. Willey 1998 Metsker S.J. Wake W.C.: Design Patterns in Java. Addison-Wesley. 2006 5

Existující knihy k Business Patterns 6

Úvod Vzory pro návrh, návrhové vzory (Design Patterns) souvislost s objektově orientovanou analýzou a návrhem. Klíčový poje znovupoužitelnost (reusability) Znovupoužitelnost v oblasti objektově orientovaných jazyků části software, které se použijí buď přímo, nebo po malém přizpůsobení využívá se dědičnosti. 7

Úvod Znovupoužitelnost je v oblasti objektově orientovaných jazyků použita na úrovni implementace zdrojového kódu. Vzory pro návrh vycházejí z práce zkušeného návrháře, ten nezačíná svoji práci od nuly, ale pokud se mu nějaký způsob řešení osvědčil snaha používat ho znovu a vylepšovat ho. Znovupoužitelnost v oblasti návrhových vzorů znamená znovupoužití znalostí získaných v průběhu návrhu. 8

Úvod Znovupoužitelnost je možné chápat v několika úrovních: dědičnost a business objekty (aplikační objekty) znovupoužitelnost na implementační úrovni návrhové vzory znovupoužitelnost v oblasti návrhu nabytých znalostí 9

Co je vzor Vzor určuje opakující se (opětovný) návrh problému, který vzniká ve specifických situacích a presentuje nějaké jejich řešení. Vzory reprezentují existující, dobře prověřené zkušenosti návrhu. Vzory identifikují a specifikují abstrakce, které jsou nad úrovní jednotlivých tříd a instancí nebo komponent. Vzory poskytují společný slovník a pochopení principů návrhu. 10

Co je vzor Vzory jsou prostředky pro dokumentaci softwarové architektury. Vzory pomáhají obsáhnout složitost software a umožňují srozumitelnost a pochopitelnost software. 11

Co je návrhový vzor Návrhový vzor je libovolná znalost, která vznikla při návrhu programového systému abstrakcí od specifických konkrétních podmínek. Nutno doplnit konkrétní fyzickou podobu takovéto znalosti. Forma zápisu vzoru pro návrh není pevně daná, je závislá na tom, čeho se zkušenost kterou chceme vyjádřit návrhovým vzorem týká. 12

Forma zápisu Model použitý při návrhu potřebuje slovní komentář, který přesněji specifikuje použité prvky a vazby v modelu a umožní pochopení problému. Nejdůležitějšími charakteristikami tohoto popisu kromě jiných bývají: kontext situace, která způsobuje vznik problému problém opakující se problém vznikající v daném kontextu řešení prověřené řešení problému (někdy alespoň částečné) 13

Kontext, problém a řešení kontext: vytvoření programového vybavení s uživatelským grafickým rozhraním problém: obyčejně je problém reprezentovaný množinou někdy protichůdně působících sil např.: uživatelské rozhraní by mělo být snadno modifikovatelné funkční jádro programového vybavení by nemělo být postiženo změnou uživatelského rozhraní 14

Kontext, problém a řešení všeobecně síly pomáhají objasnit problém řešení z různých úhlů pohledu a pomáhají tak mu porozumět ve všech detailech síly mohou působit doplňkově nebo protichůdně řešení: ukazuje, jak řešit opakující se problém nebo lépe, jak vyrovnat síly, s ním sdružené. 15

Řešení v softwarové architektuře řešení zahrnuje dva aspekty: 1. Každý vzor specifikuje jistou strukturu a prostorovou konfiguraci prvků. Řešení naznačeného problému je v rozdělené aplikace na vlastní zpracování, vstupy, výstupy (MVC). To představuje statickou strukturu řešeného problému. 2. Každý vzor specifikuje chování za běhu (run-time). Např. MVC controller dostane vstup od myši, klávesnice. Událost je transformována na požadavky služeb. 16

Řešení Tyto požadavky služeb jsou zaslány buď modelu nebo pohledům. Chování za běhu reprezentuje dynamickou stránku řešení problému. Jak účastníci spolupracují, jak je organizována práce mezi nimi? 17

Příklad Před popisem vzoru je třeba vzor identifikovat a abstrahovat od konkrétností. Při návrhu konkrétní aplikace se objevují některé analogie mezi chováním vytvářených objektů (mají shodné stavy a přechody), jejich vazbami na okolní objekty (vystupují v podobných rolích). 18

Cesty jak odhalit NV (DP) Postup, který zachycuje vztahy mezi skupinami rolí objektů. Např. benzínová pumpa objekty: zákazník role nakupujícího benzínová pumpa role prodejce auto role příjemce Abstrakcí od detailů dojdeme k návrhu obecného vzoru prodeje (orientujeme se na role). 19

Cesty jak odhalit NV (DP) Pro prodej, kýmkoli realizovaný, je typické výskyt tří rolí: prodejce kupující příjemce Zaznamenáním vzájemného vztahu a operací probíhajících mezi těmito třemi aktory, vzniká návrhový vzor. Obecný vzor prodeje je potom možné aplikovat na jakýkoli prodej. 20

Formalizace popisu řešení CRC card Class Responsibility Collaborators Class třída, její název Responsibilities funkčnost, zodpovědnost Collaborators spolupracující třídy, komponenty Jiná grafická notace než UML UML grafická notace 21

Seznam probíraných vzorů Singleton jedináček Stav State Příkaz - Command 22

Problém: Jedináček - Singleton definovat třídy tak, aby uživatel nemohl svobodně ovlivňovat počet jejich instancí chceme např. aby se vytvořila pouze jedna instance dané třídy Kontext: v mnoha aplikacích potřebujeme, aby vznikla pouze jedna instance (objekt) sdílený celou aplikací 23

Řešení: Jedináček - Singleton definovat konstruktor jako soukromý private tím je zabezpečeno, že se ke konstruktoru dostaneme pouze prostřednictvím jiné metody, která bude veřejná použít při deklaraci takové třídy modifikátor final, který zabezpečí, že třída již nemůže mít potomky (nedovolí deklaraci dalších podtříd) 24

Jedináček - Singleton přímo v deklaraci třídy se vytvoří nová instance (objekt) s daným označením, které je přístupné např. prostřednictvím metody getreference(). metoda pro získání odkazu na jediný objekt, jedináček se deklaruje jako statická, což umožňuje vytvářet instance s využitím názvu třídy 25

Grafické znázornění Ucet OsobaA OsobaC OsobaB 26

public final class Ucet { private int cislo; private int stav; private static Ucet ucetsingleton; // tridni, staticka promenna private Ucet() { // vsechny konstruktory jsou private this(0, 0); Poznámky Účet singleton private Ucet(int cislo, int stav) { this.cislo = cislo; this.stav = stav; // tovarni (factory) metoda pro ziskani instance uctu public static Ucet getinstance(){ if(ucetsingleton == null) ucetsingleton = new Ucet(1, 0); return ucetsingleton; public void vlozeni (int castka) { stav = stav + castka; public int vyber (int castka) { stav = stav - castka; return stav; 27

public String tostring() { return String.format("Cislo uctu: %d stav uctu: %d",getcislo(), getstav()); Poznámky Účet singleton 28

public class Osoba { private String jmeno; private int roknarozeni; //pripojeni pres tridni promennou private static Ucet ucet = Ucet.getInstance(); // deklarace konstruktoru public Osoba() { this("neuvedeno", 0); public Osoba(String jmeno, int roknarozeni) { this.jmeno= jmeno; this.roknarozeni = roknarozeni; public String tostring() { String tx= String.format("\nJmeno: njmeno: %s rok narozeni: %4d\nUcet: %s", getjmeno(), getroknarozeni(), ucet.tostring()); return tx; Poznámky Osoba využívá účet 1. varianta třídní proměnná ucet odkazuje na singleton jedináčka účtu public Ucet getucet(){ return ucet; public void vlozeni(int castka){ ucet.vlozeni(castka); public void vyber(int castka) { ucet.vyber(castka); 29

public class OsobaX { private String jmeno; private int roknarozeni; //private static Ucet ucet = Ucet.getInstance(); // deklarace konstruktoru public OsobaX() { this("neuvedeno", 0); public OsobaX(String jmeno, int roknarozeni) { this.jmeno= jmeno; this.roknarozeni = roknarozeni; public String tostring() { Ucet ucet = Ucet.getInstance(); String tx= String.format("\nJmeno: njmeno: %s rok narozeni: %4d\nUcet: %s", getjmeno(), getroknarozeni(), ucet.tostring()); return tx; public Ucet getucet(){ Ucet ucet = Ucet.getInstance(); return ucet; public void vlozeni(int castka){ Ucet ucet = Ucet.getInstance(); ucet.vlozeni(castka); public void tiskucet(){ Ucet ucet = Ucet.getInstance(); System.out.println("Ucet: "+ucet.tostring()); Poznámky Osoba využívá účet 2. varianta v každé metodě se musí deklarovat třídní proměnná ucet odkazující na singleton jedináčka účtu 30

public class OsobaTest { public static void main(string[] args) { Osoba o1, o2, o3; OsobaX o11, o12; o1 = new Osoba("Adam", 1988); o2 = new Osoba("Alice", 1922); o3 = new Osoba("Iveta", 1977); o11 = new OsobaX("Silvestr", 1982); o12 = new OsobaX("Renata", 1975); Poznámky OsobaTest o1.vlozeni(300); o2.vyber(200); o12.vyber(50); o11.tisk(); o3.vlozeni(750); o12.vyber(400); o1.tisk(); if(o12.getucet() == o1.getucet()) System.out.println("Ucty jsou stejne"); else System.out.println("Ucty se lisi"); 31

Problém: Vzor Command - příkaz Standardní cesta pro vykonání metody je její vyvolání. V některých situacích nejsme schopni řídit načasování (timing) kontextu, ve kterém by se měly metody volat. Dalším problémem je flexibilní zpracování návratové hodnoty metody. 32

Kontext: Vzor Command - příkaz Klient, který využívá služeb (metod) objektu volá operaci, která vrací návratovou hodnotu, podle které se rozhodne o dalším pokračování programu. Pro jednoduchost předpokládejme návrat celočíselné hodnoty např. 1 a 2 a podle jich se rozhodne jak dále. Samozřejmě je třeba ještě ošetřit jinou návratovou hodnotu, která způsobí chybu. 33

Vzor Command - příkaz Původní řešení je následující: switch (hodnota) { 1 : a.nejakaoperace( ); 2 : b.jinaoperace( ); Uvedené řešení je funkční, ale není flexibilní. Přidání další možné návratové hodnoty znamená přepsat (doplnit) uvedený kód. 34

Vzor Command - příkaz Řešení: Zaveďme rozhraní s operací execute( ). Pro každé zpracování návratové hodnoty zavedeme další třídu pod tímto rozhraním a v této třídě implementujeme metodu execute( ). Ta pak provede patřičné operace např. a.nejakaoperace( ). 35

Vzor Command - příkaz Řešení: Požadavek (metodu) zapouzdříme do podoby objektu (objektové proměnné), takže můžeme s požadavkem pracovat jako s každou jinou proměnnou, což vede k parametrizaci požadavků. (dynamické tvorbě seznamu požadavků, dosazení požadavku za jiný požadavek apod.) 36

Command diagram tříd UML 37

interface Command { void execute(); Poznámky 38

public class TridaA { private double hodnota; public TridaA(double hodnota) { this.hodnota = hodnota; public double nejakaoperace() { System.out.println("nejakaOperace - TridaA"); return Math.sqrt(hodnota); Poznámky 39

public class TridaA { private double hodnota; public TridaA(double hodnota) { this.hodnota = hodnota; public double nejakaoperace() { System.out.println("nejakaOperace - TridaA"); return Math.sqrt(hodnota); Poznámky 40

public class CalculationA implements Command{ private TridaA tridaa; public CalculationA(TridaA tridaa) { this.tridaa = tridaa; public void execute() { //implementace metody System.out.println(tridaA.nejakaOperace()); Poznámky 41

public class CalculationB implements Command { private TridaB tridab; public CalculationB(TridaB tridab) { this.tridab = tridab; public void execute() { tridab.jinaoperace(); System.out.printf("%.2f", tridab.jinaoperace()); Poznámky 42

public class CommandPattern { Poznámky public static void main(string[] args) { TridaA tridaa = new TridaA(22); TridaB tridab = new TridaB(84); CalculationA calcula = new CalculationA(tridaA); CalculationB calculb = new CalculationB(tridaB); calcula.execute(); calculb.execute(); 43

Vzor Command - příkaz Příkazy vzoru Command se dají uložit do objektu třídy Register kvalifikovaného na objekt rozhraní Command To pak vede k tomu, že se dá vytvořit dynamický seznam požadavků, které se postupně provádějí. 44

public class RegisterC { private Command pole[]; private int top; Poznámky // konstruktor public RegisterC(int pocet) { top = -1; pole = new Command[pocet]; public void vlozit(command prvek) { if ((top + 1) < pole.length) { top += 1; pole[top] = prvek; else System.out.println("Registr je obsazeny"); public Command getprvek(int i) { Command prvek=null; if (i>=0 && i< pole.length) prvek = pole[i]; else System.out.printf("%s %d %s\n","index",i,"mimo rozsah"); return prvek;... 45

public class CommandPattern{ Poznámky public static void main(string args[]) { // new Command1().execute(25); //funkční // new Command2().execute(49); Command c = new Command1(); c.execute(6); c = new Command2(); c.execute(6); RegisterC rc = new RegisterC(6); rc.vlozit(c); rc.vlozit(c); c = new Command1(); rc.vlozit(c); rc.vlozit(c); System.out.println("Vypis registru"); for (int i =0; i<=rc.gettop(); i++){ rc.getprvek(i).execute(i+3 i+3); 46

nejakaoperace - TridaA 36.0 jinaoperace - TridaB 2,45 Poznámky Vypis registru jinaoperace - TridaB 1,73 jinaoperace - TridaB 2,00 nejakaoperace - TridaA 25.0 nejakaoperace - TridaA 36.0 47

Jednodušší varianta vzoru Command Přímo třídy Command1 a Command2 implementují požadované metody. 48

interface Command { void execute(); Poznámky class Hello implements Command { public void execute() { System.out.println("Hello "); class World implements Command { public void execute() { System.out.println("World! "); class IAm implements Command { public void execute() { System.out.println("I'm the command pattern!"); 49

// An object that holds commands: class Macro { private List <Command> commands = new ArrayList <Command>(); public void add(command c) { commands.add(c); public void run() { Iterator it = commands.iterator(); while(it.hasnext()) ((Command)it.next()).execute(); Poznámky 50

public class CommandPattern{ public static void main(string args[]) { Poznámky Macro macro = new Macro(); macro.add(new Hello()); macro.add(new World()); macro.add(new IAm()); macro.run(); // další možnosti new IAm().execute(); new Hello().execute(); 51

Vzor Command Tento vzor má řadu uplatnění, např. ošetřování chybových stavů, práce s událostmi řízených programech. Operace, která se má provést je zabalena do objektu a pak se s ní dá pružně manipulovat. Klient je odstíněn od konkrétní implementace metody execute(). Konkrétní metoda je vybrána podle typu objektu, který metodu execute() aktuálně vyvolává. 52

public interface Command { public void execute(); Poznámky Příklad garáž, vrata: up, down, stop světlo: on, off, 53

public class GarageDoor { Poznámky public GarageDoor() { public void up() { System.out.println("Garage Door is Open"); public void down() { System.out.println("Garage Door is Closed"); public void stop() { System.out.println("Garage Door is Stopped"); public void lighton() { System.out.println("Garage light is on"); public void lightoff() { System.out.println("Garage light is off"); 54

public class GarageDoorOpenCommand implements Command { GarageDoor garagedoor; Poznámky public GarageDoorOpenCommand(GarageDoor garagedoor) { this.garagedoor = garagedoor; public void execute() { garagedoor.up(); 55

public class Light { Poznámky public Light() { public void on() { System.out.println("Light is on"); public void off() { System.out.println("Light is off"); 56

public class LightOffCommand implements Command { Light light; Poznámky public LightOffCommand(Light light) { this.light = light; public void execute() { light.off(); 57

public class LightOnCommand implements Command { Light light; Poznámky public LightOnCommand(Light light) { this.light = light; public void execute() { light.on(); 58

public class SimpleRemoteControl { Command slot; Poznámky public SimpleRemoteControl() { public void setcommand(command command) { slot = command; public void buttonwaspressed() { slot.execute(); 59

public class RemoteControlTest { public static void main(string[] args) { SimpleRemoteControl remote = new SimpleRemoteControl(); Light light = new Light(); GarageDoor garagedoor = new GarageDoor(); LightOnCommand lighton = new LightOnCommand(light); GarageDoorOpenCommand garageopen = new GarageDoorOpenCommand(garageDoor); LightOffCommand lightoff = new LightOffCommand(light); Poznámky remote.setcommand(lighton); remote.buttonwaspressed(); remote.setcommand(garageopen); remote.buttonwaspressed(); remote.setcommand(lightoff); remote.buttonwaspressed(); 60