Zrozum "wzór dekoratora" na przykładzie prawdziwego świata

Studiowałem Wzór dekoratora Jak udokumentowano w GOF .

Proszę, pomóż mi zrozumieć Wzór dekoratora . Czy ktoś mógłby podać przykład użycia, gdzie jest to przydatne w prawdziwym świecie?

Author: ROMANIA_engineer, 2010-04-25

12 answers

Wzór dekoratora osiąga jeden cel dynamicznego dodawania odpowiedzialność wobec każdego przedmiotu.

Rozważmy przypadek pizzerii. W pizzerii będą sprzedawać kilka odmian pizzy, a także zapewnią dodatki w menu. Teraz wyobraź sobie sytuację, w której jeśli Pizzeria ma zapewnić ceny dla każdej kombinacji pizzy i topping. Nawet jeśli są cztery podstawowe pizze i 8 różnych dodatków, aplikacja oszaleje utrzymując wszystkie te betonowe połączenie pizzy i dodatków. Oto wzór dekoratora.

Zgodnie ze wzorem dekoratora, będziesz wdrażać dodatki jako dekoratorów i pizze będą dekorowane przez dekoratorów tych dodatków. Praktycznie każdy klient chciałby, aby dodatki na jego życzenie i ostateczna kwota rachunku składać się będzie z pizzy podstawowej i dodatkowo zamówionych dodatków. Każdy dekorator wie o pizzy, którą dekoruje i której jest cena. GetPrice() metoda polewania obiektu zwróci skumulowaną cenę zarówno pizzy, jak i polewy.

EDIT

Oto kod-przykład wyjaśnienia powyżej.

public abstract class BasePizza
{
    protected double myPrice;

    public virtual double GetPrice()
    {
        return this.myPrice;
    }
}

public abstract class ToppingsDecorator : BasePizza
{
    protected BasePizza pizza;
    public ToppingsDecorator(BasePizza pizzaToDecorate)
    {
        this.pizza = pizzaToDecorate;
    }

    public override double GetPrice()
    {
        return (this.pizza.GetPrice() + this.myPrice);
    }
}

class Program
{
    [STAThread]
    static void Main()
    {
        //Client-code
        Margherita pizza = new Margherita();
        Console.WriteLine("Plain Margherita: " + pizza.GetPrice().ToString());

        ExtraCheeseTopping moreCheese = new ExtraCheeseTopping(pizza);
        ExtraCheeseTopping someMoreCheese = new ExtraCheeseTopping(moreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese: " + someMoreCheese.GetPrice().ToString());

        MushroomTopping moreMushroom = new MushroomTopping(someMoreCheese);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom: " + moreMushroom.GetPrice().ToString());

        JalapenoTopping moreJalapeno = new JalapenoTopping(moreMushroom);
        Console.WriteLine("Plain Margherita with double extra cheese with mushroom with Jalapeno: " + moreJalapeno.GetPrice().ToString());

        Console.ReadLine();
    }
}

public class Margherita : BasePizza
{
    public Margherita()
    {
        this.myPrice = 6.99;
    }
}

public class Gourmet : BasePizza
{
    public Gourmet()
    {
        this.myPrice = 7.49;
    }
}

public class ExtraCheeseTopping : ToppingsDecorator
{
    public ExtraCheeseTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 0.99;
    }
}

public class MushroomTopping : ToppingsDecorator
{
    public MushroomTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}

public class JalapenoTopping : ToppingsDecorator
{
    public JalapenoTopping(BasePizza pizzaToDecorate)
        : base(pizzaToDecorate)
    {
        this.myPrice = 1.49;
    }
}
 206
Author: this. __curious_geek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-23 18:12:45

Jest to prosty przykład dynamicznego dodawania nowego zachowania do istniejącego obiektu lub wzorca dekoratora. Ze względu na naturę dynamicznych języków, takich jak Javascript, wzorzec ten staje się częścią samego języka.

// create a message object
var message = {
    text: "Lorem ipsum dolor sit amet, consectetur adipisicing elit..."
};

// add logging behavior to the message object dynamically
message.log = function() {
    console.log(this.text);
};

// use the newly added behavior to log text
​message.log();​ // Loren ipsum...​​​​​​​​​​​​​​​
 28
Author: Anurag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-11 19:11:42

Warto zauważyć, że model we/wy Java bazuje na wzorze dekoratora. Warstwę tego czytelnika na wierzchu tego czytelnika na wierzchu of...is prawdziwy przykład dekoratora.

 16
Author: frankc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-26 14:39:08

Przykład-scenariusz-powiedzmy, że piszesz moduł szyfrujący. To szyfrowanie może zaszyfrować czysty plik za pomocą standardu szyfrowania DES - Data. Podobnie, w systemie możesz mieć szyfrowanie jako AES-Advance encryption standard. Możesz również mieć kombinację szyfrowania - najpierw DES, a następnie AES. Albo najpierw AES, potem DES.

Dyskusja - jak poradzisz sobie z tą sytuacją? Nie można dalej tworzyć obiektu takich kombinacji - na przykład-AES i DES - łącznie 4 kombinacje. W związku z tym musisz mieć 4 pojedyncze obiekty, które staną się złożone wraz ze wzrostem typu szyfrowania.

Rozwiązanie-budować kombinacje stosu w zależności od potrzeb - w czasie pracy. Kolejną zaletą tego podejścia stosu jest to, że można go łatwo rozluźnić.

Oto rozwiązanie-w C++.

Po pierwsze, potrzebujesz klasy bazowej-podstawowej jednostki stosu. Możesz myśleć jak podstawa stosu. W tym przykładzie jest jasne plik. Podążajmy zawsze za polimorfizmem. Stwórz najpierw klasę interfejsu tej podstawowej jednostki. W ten sposób można go wdrożyć, jak chcesz. Ponadto nie musisz myśleć o zależności, włączając w to tę podstawową jednostkę.

Oto Klasa interfejsu -

class IclearData
{
public:

    virtual std::string getData() = 0;
    virtual ~IclearData() = 0;
};

IclearData::~IclearData()
{
    std::cout<<"Destructor called of IclearData"<<std::endl;
}

Teraz zaimplementuj tę klasę interfejsu -

class clearData:public IclearData
{
private:

    std::string m_data;

    clearData();

    void setData(std::string data)
        {
            m_data = data;
        }

public:

    std::string getData()
    {
        return m_data;
    }

    clearData(std::string data)
    {
        setData(data);
    }

    ~clearData()
    {
        std::cout<<"Destructor of clear Data Invoked"<<std::endl;
    }

};

Teraz zróbmy klasę abstrakcyjną dekoratora-która może być rozszerzona o tworzenie dowolnego rodzaju smaków - tutaj smak jest typem szyfrowania. Ten dekorator klasa abstrakcyjna jest powiązana z klasą bazową. Tak więc dekorator "jest" rodzajem klasy interfejsu. Dlatego musisz użyć dziedziczenia.

class encryptionDecorator: public IclearData
{

protected:
    IclearData *p_mclearData;

    encryptionDecorator()
    {
      std::cout<<"Encryption Decorator Abstract class called"<<std::endl;
    }

public:

    std::string getData()
    {
        return p_mclearData->getData();
    }

    encryptionDecorator(IclearData *clearData)
    {
        p_mclearData = clearData;
    }

    virtual std::string showDecryptedData() = 0;

    virtual ~encryptionDecorator() = 0;

};

encryptionDecorator::~encryptionDecorator()
{
    std::cout<<"Encryption Decorator Destructor called"<<std::endl;
}

Teraz zróbmy klasę dekoratora betonu - Typ szyfrowania-AES -

const std::string aesEncrypt = "AES Encrypted ";

class aes: public encryptionDecorator
{

private:

    std::string m_aesData;

    aes();

public:

    aes(IclearData *pClearData): m_aesData(aesEncrypt)
    {
        p_mclearData = pClearData;
        m_aesData.append(p_mclearData->getData());
    }

    std::string getData()
        {
            return m_aesData;
        }

    std::string showDecryptedData(void)
    {
        m_aesData.erase(0,m_aesData.length());
        return m_aesData;
    }

};

Powiedzmy, że typem dekoratora jest DES-

Const std:: string desEncrypt = "des Encrypted";

class des: public encryptionDecorator
{

private:

    std::string m_desData;

    des();

public:

    des(IclearData *pClearData): m_desData(desEncrypt)
    {
        p_mclearData = pClearData;
        m_desData.append(p_mclearData->getData());
    }

    std::string getData(void)
        {
            return m_desData;
        }

    std::string showDecryptedData(void)
    {
        m_desData.erase(0,desEncrypt.length());
        return m_desData;
    }

};

Zróbmy kod klienta, aby użyć tej klasy dekoratora-

int main()
{
    IclearData *pData = new clearData("HELLO_CLEAR_DATA");

    std::cout<<pData->getData()<<std::endl;


    encryptionDecorator *pAesData = new aes(pData);

    std::cout<<pAesData->getData()<<std::endl;

    encryptionDecorator *pDesData = new des(pAesData);

    std::cout<<pDesData->getData()<<std::endl;

    /** unwind the decorator stack ***/
    std::cout<<pDesData->showDecryptedData()<<std::endl;

    delete pDesData;
    delete pAesData;
    delete pData;

    return 0;
}

Zobaczysz następujące wyniki -

HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Abstract class called
DES Encrypted AES Encrypted HELLO_CLEAR_DATA
AES Encrypted HELLO_CLEAR_DATA
Encryption Decorator Destructor called
Destructor called of IclearData
Encryption Decorator Destructor called
Destructor called of IclearData
Destructor of clear Data Invoked
Destructor called of IclearData

Oto Diagram UML-Klasa reprezentacji it. W przypadku, chcesz pominąć kod i skupić się na aspekcie projektowania.

Tutaj wpisz opis obrazka

 7
Author: dexterous_stranger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-02 07:24:59

Czym jest wzorzec projektowy dekoratora w Javie.

Formalna definicja wzorca dekoratora z książki GoF (Design Patterns: Elements of reusable Object-Oriented Software, 1995, Pearson Education, Inc. Publikując jako Pearson Addison Wesley) mówi, że możesz,

" dołączanie dodatkowych obowiązków do obiektu dynamicznie. Dekoratorzy zapewnij elastyczną alternatywę dla podklasowania w celu rozszerzenia funkcjonalności."

Powiedzmy, że mamy pizzę i chcemy ją udekorować z dodatkami takimi jak Masala z kurczaka, cebula i ser Mozzarella. Zobaczmy, jak zaimplementować go w Javie ...

Program do zademonstrowania jak zaimplementować wzorzec projektowy dekoratora w Javie.

Pizza.java:
<!-- language-all: lang-html -->

package com.hubberspot.designpattern.structural.decorator;

public class Pizza {

public Pizza() {

}

public String description(){
    return "Pizza";
}

}



package com.hubberspot.designpattern.structural.decorator;

public abstract class PizzaToppings extends Pizza {

public abstract String description();

}

package com.hubberspot.designpattern.structural.decorator;

public class ChickenMasala extends PizzaToppings {

private Pizza pizza;

public ChickenMasala(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + " with chicken masala, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class MozzarellaCheese extends PizzaToppings {

private Pizza pizza;

public MozzarellaCheese(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "and mozzarella cheese.";
}
}



package com.hubberspot.designpattern.structural.decorator;

public class Onion extends PizzaToppings {

private Pizza pizza;

public Onion(Pizza pizza) {
    this.pizza = pizza;
}

@Override
public String description() {
    return pizza.description() + "onions, ";
}

}



package com.hubberspot.designpattern.structural.decorator;

public class TestDecorator {

public static void main(String[] args) {

    Pizza pizza = new Pizza();

    pizza = new ChickenMasala(pizza);
    pizza = new Onion(pizza);
    pizza = new MozzarellaCheese(pizza);

    System.out.println("You're getting " + pizza.description());

}

}
 3
Author: Jonty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-22 16:49:24

Wzór dekoratora pomaga zmienić lub skonfigurować funkcjonalność obiektu poprzez łączenie z innymi podobnymi podklasami tego obiektu.

Najlepszym przykładem mogą być Klasy InputStream i OutputStream w java.io pakiet

    File file=new File("target","test.txt");
    FileOutputStream fos=new FileOutputStream(file);
    BufferedOutputStream bos=new BufferedOutputStream(fos);
    ObjectOutputStream oos=new ObjectOutputStream(bos);


    oos.write(5);
    oos.writeBoolean(true);
    oos.writeBytes("decorator pattern was here.");


//... then close the streams of course.
 3
Author: huseyin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-08 19:45:48

W swojej pracy używałem szeroko wzorów dekoratorskich. Zrobiłem post na moim blogu o tym, jak z niego korzystać z logowaniem.

 2
Author: Ismael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-20 23:42:26

Dekorator:

  1. Dodaj zachowanie do obiektu w czasie wykonywania . Dziedziczenie jest kluczem do osiągnięcia tej funkcjonalności, co jest zarówno zaletą, jak i wadą tego wzoru.
  2. wzmacnia zachowanie interfejsu.
  3. dekorator może być postrzegany jako zdegenerowany kompozyt z tylko jednym składnikiem. Jednak dekorator dodaje dodatkowe obowiązki - nie jest przeznaczony do agregacji obiektów.
  4. Klasa dekoratora deklaruje relację składu do interfejsu LCD (najniższy mianownik klasy), A Ten element danych jest inicjowany w jego konstruktorze.
  5. dekorator jest zaprojektowany, aby umożliwić dodawanie obowiązków do obiektów bez podkategorii
[[2]}zobacz artykuł sourcemaking Aby uzyskać więcej szczegółów.

Decorator (Abstract) : jest to abstrakcyjna klasa / interfejs, która implementuje interfejs komponentu. Zawiera interfejs komponentu. W przypadku braku tej klasy, potrzebujesz wielu podklas Betonowychkoratory dla różnych kombinacji. Skład komponentu zmniejsza niezbedne podklasy.

JDK przykład:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
        char c = (char)bis.read();
        System.out.println("Char: "+c);;
}

Spójrz na poniższe pytanie dotyczące diagramu UML i przykładów kodu.

Wzór dekoratora dla IO

Przydatne artykuły:

Journaldev

Wikipedia

prawdziwe słowo przykład wzoru dekoratora: vendingmachinedecorator zostało wyjaśnione @

Kiedy stosować wzór dekoratora?

Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();

beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();
W powyższym przykładzie herbata lub kawa (napój) została ozdobiona cukrem i cytryną.
 2
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-22 15:49:32

Wzór dekoratora osiąga jeden cel dynamiczne dodawanie obowiązków do dowolnego obiektu.

Java I / O Model jest oparty na wzorze dekoratora.

Java IO jako wzór dekoratora

 2
Author: ChandraBhan Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-29 06:28:01

Wzorzec dekoratora pozwala dynamicznie dodawać zachowanie do obiektów.

Weźmy przykład, gdzie trzeba zbudować aplikację, która oblicza cenę różnych rodzajów hamburgerów. Musisz obsługiwać różne odmiany hamburgerów, takie jak "duży" lub "z serem", z których każdy ma cenę w stosunku do podstawowego hamburgera. Np. dodaj 10 $za burger z serem, dodaj dodatkowe 15 $za duży burger itp.

W tym przypadku można pokusić się o stworzenie podklasy do zajmij się tym. Możemy to wyrazić w Rubim jako:

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

W powyższym przykładzie Klasa BurgerWithCheese dziedziczy po Hamburgerze i nadpisuje metodę ceny, aby dodać $15 do ceny zdefiniowanej w klasie super. Można również utworzyć klasę LargeBurger i określić cenę w stosunku do hamburgera. Ale musisz również zdefiniować nową klasę dla kombinacji "dużych " i"z serem".

Co się stanie, jeśli będziemy musieli podać "burger z frytkami"? Mamy już 4 klasy do opanowania te kombinacje, i będziemy musieli dodać 4 więcej do obsługi wszystkich kombinacji właściwości 3 - "duży" ," z serem " i "z frytkami". Potrzebujemy teraz 8 klas. Dodaj kolejną nieruchomość i będziemy potrzebować 16. To będzie rosło jak 2^n. Zamiast tego spróbujmy zdefiniować BurgerDecorator, który przyjmuje obiekt hamburgera:
class BurgerDecorator
  def initialize(burger)
    self.burger = burger
  end
end

class BurgerWithCheese < BurgerDecorator
  def price
    self.burger.price + 15
  end
end

burger = Burger.new
cheese_burger = BurgerWithCheese.new(burger)
cheese_burger.price   # => 65

W powyższym przykładzie stworzyliśmy klasę BurgerDecorator, z której Klasa BurgerWithCheese dziedziczy. Możemy również reprezentować "dużą" odmianę tworząc Klasa largeburgera. Teraz możemy zdefiniować duży burger z serem w czasie pracy jako:

b = LargeBurger.new(cheese_burger)
b.price  # => 50 + 15 + 20 = 85

Pamiętasz, jak użycie dziedziczenia do dodania wariacji "z frytkami" wiązałoby się z dodaniem 4 kolejnych podklas? Z dekoratorami stworzylibyśmy tylko jedną nową klasę, BurgerWithFries, aby obsłużyć nową odmianę i obsłużyć ją w czasie wykonywania. Każda nowa nieruchomość potrzebowałaby więcej dekoratorów, aby pokryć wszystkie permutacje.

PS. Jest to krótka wersja artykułu, o którym pisałem używając Wzór dekoratora w Ruby , który możesz przeczytać, jeśli chcesz poznać bardziej szczegółowe przykłady.

 1
Author: Nithin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-23 18:14:21

Jest przykład na Wikipedii o dekorowaniu okna paskiem przewijania:

Http://en.wikipedia.org/wiki/Decorator_pattern

Oto kolejny bardzo 'realny' przykład "członka zespołu, kierownika zespołu i menedżera", który ilustruje, że wzór dekoratora jest niezastąpiony przy prostym dziedziczeniu:

Https://zishanbilal.wordpress.com/2011/04/28/design-patterns-by-examples-decorator-pattern/

 1
Author: gm2008,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-27 21:11:35

Dekorator Design Pattern : Ten wzorzec pomaga modyfikować właściwości obiektu w czasie wykonywania. Zapewnia różne smaki do obiektu i daje elastyczność wyboru składników, które chcemy użyć w tym smaku.

Przykład Prawdziwego Życia: Powiedzmy, że masz główne miejsce w kabinie w locie. Teraz możesz wybrać wiele udogodnień z siedziskiem. Każde udogodnienie ma swój własny koszt związany z nim. Teraz, jeśli użytkownik wybierze Wifi i premium food, będzie opłata za miejsce + wifi + jedzenie premium.

Tutaj wpisz opis obrazka

W tym przypadku wzór dekoratora może nam naprawdę pomóc. Odwiedź powyższy link, aby dowiedzieć się więcej o wzorze dekoratora i realizacji jednego prawdziwego przykładu.

 0
Author: Ajit Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-30 14:40:10