Dizajn paterni
Decorator, Factory



                 dr Zoran Jeremić
                     zoran.jeremic@gmail.com




                                               1
Strukturni paterni

DECORATOR


                     2
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
4
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
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
Opis problema




                7
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
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
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
Primena na opisani problem


 Započinjemo sa DarkRoast objektom




 Kupac je tražio Mocha, tako da kreiramo Mocha objekat
  tako da obuhvata DarkRoast.




                                                          11
Primena na opisani problem


 Kupac takođe želi šlag (Whip), pa kreiramo Whip
  dekorator i smeštamo Mocha unutar njega.




                                                    12
Izračunavanje cene




                     13
Decorator – dijagram klasa




                             14
Dijagram klasa kafeterije




                            15
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
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
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
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
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
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
Paterni kreiranja

FACTORY


                    22
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
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
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
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
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
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
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
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
Dijagram klasa




                 31

T 3.8 design paterni (c)

  • 1.
    Dizajn paterni Decorator, Factory dr Zoran Jeremić zoran.jeremic@gmail.com 1
  • 2.
  • 3.
    Opis problema  Kaojedan 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
  • 4.
  • 5.
    Opis problema  Osimkafe, 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čiglednoje 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
  • 7.
  • 8.
    Implementacija klasa public classBeverage { 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 opisaniproblem  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 opisaniproblem  Započinjemo sa DarkRoast objektom  Kupac je tražio Mocha, tako da kreiramo Mocha objekat tako da obuhvata DarkRoast. 11
  • 12.
    Primena na opisaniproblem  Kupac takođe želi šlag (Whip), pa kreiramo Whip dekorator i smeštamo Mocha unutar njega. 12
  • 13.
  • 14.
  • 15.
  • 16.
    Implementacija klasa Beveragei 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 publicclass 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 publicclass 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 classStarbuzzCoffee { 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
  • 22.
  • 23.
    Opis problema  Kadakoristimo 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  Kodpisan 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(Stringtype){ 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(Stringtype){ 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 publicclass 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 classPizzaStore { 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
  • 31.