Dizajn paterni Command, Template method, Prototype, Decorator
dr Zoran Jeremić
[email protected]
Paterni ponašanja
COMMAND
Paterni ponašanja
COMMAND
Ovaj patern će vam omogućiti enkapsulaciju na nivou pozivanja metoda, tako da objekat koji poziva neku obradu ne mora da vodi računa o tome kako funkcioniše ta obrada. Osim toga, omogućava vam poništavanje (undo) izvršen izvršenih ih operac operacija ija..
Problem daljinskog upravljača
Pogled na klase proizvođača uređaja
Problem koji treba rešiti
Imamo jednostavan daljinski upravljač sa većim brojem on i off dugmadi i skup klasa različitih proizvođača koje se u značajnoj meri razlikuju.
Metode on(), off(), setTemperature(), setVolume(), setDirection ...
Možemo očekivati još različitih proizvođača u budućnosti i svaki put je potrebno menjati postojeću implementaciju. Daljinski je “glup” i prepoznaje samo generičke zahteve. Na koji način ćemo dizajnirati akcije kao što su “Uključi svetlo”, “otvori garažu”...
Rešenje problema daljinskog upravljača
Command patern omogućava razdvajanje objekta koji zahteva akciju od objekta koji izvršava akciju.
Objekat koji zahteva akciju je daljinski, a objekat koji izvršava je jedna od klasa proizvođača.
Na koji način implementirati jednostavan daljinski upravljač
Na koji način implementirati daljinski upravljač
Korišćenje Command objekta
Metoda za testiranje daljinskog upravljača
Zadatak za samostalni rad
Potrebno je implementirati GarageDoorOpenCommand klasu
Šta će biti output Izvršenja navedene test metode?
Command pattern definisan Namena: Enkapsulira zahtev kao objekat čime omogućava parametrizaciju klijenata sa razli čitim zahtevima, redovima za čekanje, ili zahtevima za formiranje dnevnika rada, i podržava operacije čije se dejstvo može poništiti. Problem: Potrebno je da prosle đuje zahteve objekata bez ikakvog znanja o operaciji koja se zahteva ili o primaocu zahteva.
Implementacija daljinskog upravljača
Implementacija daljinskog upravljača
Još primera upotrebe: Naručivanje obroka u restoranu
Dijagram klasa: Naručivanje obroka u restoranu
Još primera upotrebe
Još primera upotrebe
Meniji implementirani korišćenjem Command
Svaki izbor u Menu klasi je instanca MenuItem klase. Klasa Application kreira ove menije i njihove elemente kao i ostatak korisničkog interfejsa. Klasa Application takođe čuva podatak o Document objektima koje je korisnik otvorio. instance konkretne Command podklase. Kada korisnik selektuje MenuItem, MenuItem poziva Execute na svojoj komandi, i Execute izvršava operaciju.
Još primera upotrebe
MenuItem ne zna koje podklase klase Command koristi. Command podklase čuvaju prijemnik zahteva i pozivaju jednu ili više operacija na prijemniku <
> Na primer, PasteCommand podržava paste teksta sa . je Document objekat. Execute operacija poziva Paste na primajućem Document objektu.
Command - primenljivost
Command upotrebite u sledećim slučajevima:
Kada hoćete da parametrizujete klijente različitim zahtevima. Kada hoćete da se zahtevi isporučuju kroz red čekanja, Kada hoćete da se pravi dnevnik (log) zahteva, .
Paterni ponašanja
TEMPLATE METHOD
Ovaj patern će vam omogućiti enkapsulaciju delova algoritama tako da se podklase mogu ugnjezditi unutar algoritama.
Problem: Spremanje kafe i čaja u kafematu
•
Recept za kafu
– – – –
Prokuvati vodu Staviti kafu u ključalu vodu Sipati kafu u šolju Dodati šećer i mleko
•
Recept za čaj
– – – –
Prokuvati vodu Staviti čaj u ključalu vodu Sipati čaj u šolju Dodati limun
Klasa Coffee public class Coffee { void prepareRecipe() { boilWater(); brewCoffeeGrinds(); pourInCup(); addSugarAndMilk(); } pu c vo o a er System.out.println(“Boiling water”); } public void brewCoffeeGrinds() { System.out.println(“Dripping Coffee through filter”); } public void pourInCup() { System.out.println(“Pouring into cup”); } public void addSugarAndMilk() { System.out.println(“Adding Sugar and Milk”); }
Klasa Tea public class Tea { void prepareRecipe() { boilWater(); steepTeaBag(); pourInCup(); addLemon(); } public void boilWater() { System.out.println(“Boiling water”); } public void steepTeaBag() { System.out.println(“Steeping the tea”); } public void addLemon() { System.out.println(“Adding Lemon”); } public void pourInCup() { System.out.println(“Pouring into cup”); } }
Dijagram klasa sa apstrakcijom
Problem
Prokuvati vodu
Staviti kafu (ili čaj) u ključalu vodu
Sipati kafu (ili čaj) u šolju
Dodati šećer i mleko (ili limun)
Coffee void prepareRecipe() { boilWater(); brewCoffeeGrinds(); pourInCup(); addSugarAndMilk();
Tea void prepareRecipe() { boilWater(); steepTeaBag(); pourInCup(); addLemon();
Ove dve su već abstrakovane u osnovnu klasu
Nisu abstrakovane ali su u suštini iste samo primenjuju drugi napitak.
void prepareRecipe() { boilWater(); brew(); pourInCup(); addCondiments();
Klasa CaffeineBeverage public abstract class CaffeineBeverage { void prepareRecipe() { boilWater(); brew();
pourInCup(); addCondiments);
} abstract void brew(); abstract void addCondiments();
public void boilWater() { System.out.println(“Boiling water”); } public void pourInCup() { System.out.println(“Pouring into cup”); } }
Klase Coffee i Tea public class Coffee extends CaffeineBeverage{ public void brew() { System.out.println(“Dripping Coffee through filter”); } public void addCondiments() { System.out.println(“Adding Sugar and Milk”); }
public class Tea extends CaffeineBeverage{ public void brew() { System.out.println(“Steeping the tea”); } public void addCondiments() { System.out.println(“Adding Lemmon”); } }
Abstraktna Template klasa
•
Možemo imati i konkretne metode koje ne rade ništa po defaultu. One se nazivaju „priključne“ (hook) metode. Podklase mogu re mp emen ra ove metode, ali i ne moraju.
Abstraktna CaffeineBeverage klasa
Template method
Namena
Definiše skelet algoritma u nekoj operaciji prepuštajući implementaciju nekih koraka potklasi. Template Template metod dozvoljava da potklase redefinišu neke korake altoritma ne menjajući strukturu altoritma.
Template method - primer
Graditelji kuća koriste Template metod kada razvijaju novi ogranak. Tipi čan ogranak se sastoji od ograni čenog broja planova spratova, sa razli čitim varijantama za svaki plan sprata. Unutar plana sprata, osnova, okviri, vodovodne cevi i električna instalacija su identični za svaku kuću. Varijacije se uvode u kasnijim fazama konstrukcije da bi proizveli veći broj modela.
Primer
Template method - struktura
Template method - primenljivost
Za impementiranje nepromenljivih delova algoritma na jednom mestu i prepuštanje implementacije ponašanja koje se menja potklasama. Kada ponašanje zajedničko za potklase treba izdvojiti i
koda. Za kontrolisanje proširivanja potklasa. Možete da definišete šablonski metod koji na određenim tačkama poziva “priljučene” operacije i na taj način dopušta proširivanje samo u tim tačkama.
Template method - posledice
Template method poziva sledeće vrste operacija:
Konkretne operacije (iz ConcreteClass ili klijentske klase) Konkretne operacije AbstractClass klase Primitivne operacije (tj. Apstraktne operacije) Priključne operacije – obezbeđuju podrazumevano ponašanje koje potklase mogu po potrebi da prošire. Priljučena operacija često podrazumevano ništa ne radi.
Gradivni paterni
PROTOTYPE
Prototype (prototip)
Kloniranje je primer Prototype paterna
Kako prototip patern funkcioniše u realnom životu clone
request
deliver
clone
Prototype
Određuje vrste objekata koji se prave koristeći prototipski primerak i pravi nove objekte kopiranjem tog prototipa.
Prototipovi novih proizvoda se često izrađuju pre pune proizvodnje, ali u ovom primeru prototip je pasivan i ne učestvuje u kopiranju samog sebe. Deoba ćelija, koja rezultuje u dobijanju dve identične ćelije, je primer kako prototip igra aktivnu ulogu u kopiranju samog sebe i demonstrira Prototype patern. Kada se ćelija deli, dobijaju se dve identične ćelije. Drugim rečima ćelija klonira samu sebe.
Motivacija – primer dijaloga
Vidim da imate račun za struju
Potreban mi je duplikat tog računa
Da, imam
U redu. Pozvaću elektrodistribuciju da mi izdaju još jedan primerak
Mora da postoji neki jednostavniji način da to rešimo
Ne, nemam softver koji oni koriste da bih mogao da vam napravim još jedan primerak
Motivacija – drugi dijalog
Vidim da imate račun za struju
Možete li da mi napravite kopiju tog računa?
Da, imam
Naravno. Staviću ga u fotokopir mašinu.
Super. Sada oboje imamo kopije računa.
Da, ali vi morate da platite račun
Prototype - primenljivost
Kada se koristi Prototype patern?
Kada kreiranje objekta oduzima puno vremena i kada već imamo veoma sličnu instancu objekta. Umesto da kreiramo novi kompleksni objekat, samo ćemo kopirati postojeći sličan objekat i modifikovati ga prema našim potrebama.
Kada se klonira objekat direktno dobijamo novi željeni objekat bez eksplicitnog modifikovanja kreiranog objekta. Instanca koja se kopira treba sama da obezbedi sposobnost kopiranja
Struktura
Uloge
Prototype
Interfejs ili abstraktna klasa Definiše metodu za kloniranje objekta
Uloge
ConcretePrototype
Klasa koja implementira Prototype U suštini ima način da kopira samog sebe Duboka ili plitka kopija
Podrška u programskim jezicima
C#
IClonable MemberwiseClone
Java
Clonable clone
Primer
Prototype - posledice
Dodavanje i uklanjanje proizvoda u vreme izvršavanja Određivanje novih objekata menjanjem vrednosti Određivanje novih objekata menjanjem strukture
Dinamičko konfigurisanje aplikacije klasama
Strukturni paterni
DECORATOR
Kada savladate tehniku dekoratora moći ćete da date svojim objektima nove odgovnosti bez ikakve izmene code-a klasa koje se proširuju.
Opis problema
Kao jedan od vodećih svetskih lanaca sa coffee shop konceptom, Costa Coffee u proseku otvara po pet kafeterija nedeljno, na različitim lokacijama širom sveta. Zbog tako velikog rasta, neprekidno se trude da obogate svo u onudu novim na icima.
Opis problema
Opis problema – eksplozija klasa
Osim kafe, moguće je naručiti i priloge, kao što su šlag, mleko, soja, čokolada, i svi oni utiču na cenu, pa ih je potrebno ugraditi u sistem.
Opis problema
Očigledno je dati model komplikovan i težak za održavanje. Šta se dešava kada cena mleka skoči? Možemo li osnovnoj klasi Beverage dodati promenjlive koje pokazuju da li napitak ima neki dodatak?
Opis problema
Implementacija klasa public class Beverage { double cost() { //izracunati cenu sa dodacima }
public class DarkRoast extends Beverage { public DarkRoast(){ description=“Most Excellent Dark Roast”; } double cost() { . //izracunati cenu tipa kafe }
Ovakav model značajno smanjuje broj klasa, ali određeni problemi i dalje nisu rešeni.
Šta se dešava u slučaju budućih promena (promena cene, novi prilozi, novi napici)?
Decorator
Namena
Dinamičko dodavanje funkcionalnosti postojećim objektima, Alternativa podklasama, Fleksibilan dizajn, .
Primenljivost
Legacy sistemi, Dodavanje funkcionalnosti kontrolama,
Kako Decorator funkcioniše
Umotava objekte
Primena na opisani problem
Pretpostavimo da kupac želi DarkRoast sa čokoladom (Mocha) i šlagom (Whip) Uzmite DarkRoast objekat Dekorišite ga Mocha objektom Dekorišite ga Whip objektom Pozovite cost() metodu i koristite delegiranje da bi dodali troškove priloga.
Primena na opisani problem
Započinjemo sa DarkRoast objektom
, tako da obuhvata DarkRoast.
Primena na opisani problem
Kupac takođe želi šlag (Whip), pa kreiramo Whip dekorator i smeštamo Mocha unutar njega.
Izračunavanje cene
Decorator – dijagram klasa
Dijagram klasa kafeterije
Implementacija klasa Beverage i CondimentDecorator public abstract class Beverage { String description=“Unknown Beverage”; public String getDescription(){ return description; } public abstract double cost(); } public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); }
Implementacija konkretnih komponenti public class Espresso extends Beverage { public Espresso(){ description=“Espresso”; } public double cost(){ return 1.99; } public class HouseBlend extends Beverage { public Espresso(){ description=“House Blend Coffe”; } public double cost(){ return 0.89; } }
Implementacija konkretnih dekoratora public class Mocha extends CondimentDecorator { Beverage beverage; public Mocha(Beverage beverage){ this.beverage=beverage; } public String getDescription(){ . } public abstract double cost(){ return 0.20 + beverage.cost(); } }
“,
”
Korišćenje dekoratora public class StarbuzzCoffee { 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 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()); } }