3. 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
svoju ponudu novim napicima.
3
5. Opis problema
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.
5
6. Opis problema
Očigledno je dati model komplikovan i težak za održavanje.
Šta se dešava kada cena mleka skoči?
Šta se deš
Možemo li osnovnoj klasi Beverage dodati promenjlive koje
pokazuju da li napitak ima neki dodatak?
6
8. Implementacija klasa
public class Beverage { public class DarkRoast extends
double cost() { Beverage {
//izracunati cenu sa dodacima public DarkRoast(){
description=“Most Excellent Dark
} Roast”;
}
double cost() {
super.coast();
//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)?
8
9. Decorator
Namena
Dinamički dodeljuje dodatnu odgovornost objektima. Decorator
obezbeđuje fleksibilnu alternativu proširivanju podklasa zbog
proširivanja funkcionalnosti.
Problem
Želite da dodate ponašanje ili stanje pojedinačnim objektima u
vreme izvršenja. Nasleđivanje nije moguće jer je statičko i
primenjuje se na čitavu klasu.
9
10. 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.
10
11. Primena na opisani problem
Započinjemo sa DarkRoast objektom
Kupac je tražio Mocha, tako da kreiramo Mocha objekat
tako da obuhvata DarkRoast.
11
12. Primena na opisani problem
Kupac takođe želi šlag (Whip), pa kreiramo Whip
dekorator i smeštamo Mocha unutar njega.
12
16. 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();
}
16
17. 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;
}
}
17
18. Implementacija konkretnih dekoratora
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage=beverage;
}
public String getDescription(){
return beverage.getDescription() + “, Mocha”;
}
public abstract double cost(){
return 0.20 + beverage.cost();
}
}
18
19. 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 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());
}
}
19
20. Decorator - Primenljivost
Za dodavanje odgovornosti pojedinačnim objektima na
dinamički i transparentan način, tj. bez uticaja na druge
objekte,
Za odgovornosti koje mogu da se povuku,
Kada proširenje pomoću pravljenja podklasa nije
praktično.
20
21. Decorator - posledice
Prednosti:
Veća fleksibilnost od staičkog nasleđivanja,
Izbegavaju se klase prebogate karakteristikama visoko u
hijerarhiji.
Nedostaci:
Dekorator i njegova komponenta nisu identični. Dekorator služi
kao transparentni omotač, pa prema tome ne bi trebalod a se
oslanjate na identitet objekta kada koristite dekoratere.
Mnogo malih objekata. Ako se u projektu mnogo koristi
Decorator, dobiće se sistem sastavljen od mnogo sličnih malih
objekata. Objekti se razlikuju samo po tome kako su međusobno
povezani, a ne prema klasi ili vrednostima promenljivih. U
takvom sistemu teško je analizirati greške.
21
23. Opis problema
Kada koristimo new mi zapravo instanciramo konkretnu
klasu, tako da je to definitivno implementacija a ne
interfejs.
Duck duck = new MallardDuck();
Kada imamo skup povezanih konkretnih klasa, često
pišemo kod poput ovog:
Duck duck;
If (picnic) {
duck = new MallardDuck();
} else if (hunting) {
duck = new DecoyDuck();
}else if (inBathTub){
duck = new RubberDuck();
}
23
24. Opis problema
Kod pisan kroz interfejse će raditi kroz polimorfizam sa
bilo kojom novom klasom koja implementira interfejs.
Međutim kada imamo dostra konkretnih klasa, kod se
mora menjati dodavanjem novih konkretnih klasa.
24
25. Opis problema
Zbog fleksibilnosti
Pizza je abstraktna
Pizza orderPizza(){ klasa
Pizza pizza = new Pizza ();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
25
26. Opis problema
Pizza orderPizza(String type){ Sada prosleđujemo
Pizza pizza = new Pizza (); vrstu pice kao
if (type.equals(“cheese”)) { argument
pizza = new CheesePizza();
} else if (type.equals(“greek”) { Na osnovu vrste pice
pizza = new GreekPizza();
} else if (type.equals(“pepperoni”) {
instanciramo
pizza = new PepperoniPizza(); konkretnu klasu i
} dodeljujemo je
promenljivoj pizza
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
26
27. Opis problema
Pizza orderPizza(String type){
Pizza pizza = new Pizza (); Kod se mora
if (type.equals(“cheese”)) { konstantno menjati u
pizza = new CheesePizza();
skladu sa ponudama
} else if (type.equals(“greek”) {
pizza = new GreekPizza(); picerije
} else if (type.equals(“pepperoni”) {
pizza = new PepperoniPizza();
} else if (type.equals(“clam”)) {
pizza = new ClamPizza();
} else if (type.equals(“veggie”) {
pizza = new VeggiePizza();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
27
28. Enkapsulacija kreiranja objekta
if (type.equals(“cheese”)) {
pizza = new CheesePizza();
} else if (type.equals(“pepperoni”) {
pizza = new PepperoniPizza();
} else if (type.equals(“clam”)) {
pizza = new ClamPizza();
Pizza orderPizza(String type){ } else if (type.equals(“veggie”) {
Pizza pizza = new Pizza (); pizza = new VeggiePizza();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
28
29. Jednostavan pizza factory
public class SimplePizzaFactory {
Metodu createPizza()
public Pizza createPizza(String type) { koriste svi klijenti za
Pizza pizza = null;
if (type.equals(“cheese”)) { instanciranje novih
pizza = new CheesePizza(); objekata.
} else if (type.equals(“pepperoni”)) {
pizza = new PepperoniPizza(); Ovaj kod je još uvek
} else if (type.equals(“clam”)) {
pizza = new ClamPizza(); parametrizovan
} else if (type.equals(“veggie”)) { vrstom pice, kao i u
pizza = new VeggiePizza(); originalnoj
}
return pizza; orderPizza() metodi.
}
}
29
30. PizzaStore klasa
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) { PizzaStore klasi se
this.factory = factory; prosleđuje factory kroz
} konstruktor
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizza(type); orderPizza() metoda
koristi factory da kreira
pizza.prepare();
pizza.bake(); picu jednostavnim
pizza.cut(); prosleđivanjem tipa pice
pizza.box();
return pizza;
}
// other methods here
}
30