Поймите "шаблон декоратора" с примером реального мира


Я изучал Шаблон "Декоратор" как описано в г.

пожалуйста, помогите мне понять Шаблон "Декоратор". Может ли кто-нибудь привести пример использования, где это полезно в реальном мире?

12 149

12 ответов:

шаблон декоратора достигает одной цели динамического добавления ответственность перед любым объектом.

рассмотрим случай с пиццерией. В пиццерии они будут продавать несколько сортов пиццы, и они также будут предоставлять начинки в меню. Теперь представьте себе ситуацию, когда если пиццерия должна обеспечить цены на каждую комбинацию пиццы и долива. Даже если есть четыре основных пиццы и 8 различных начинок, приложение будет сходите с ума, поддерживая все эти конкретные комбинации пиццы и начинки.

вот идет шаблон декоратора.

в соответствии с рисунком декоратора, вы будете реализовывать начинки в качестве декораторов и пиццы будут украшены декораторами этих начинок. Практически каждый клиент хотел бы начинки своего желания и окончательный счет-сумма будет состоять из базовых пицц и дополнительно заказанных начинок. Каждый долива декоратор будет знать о пиццах, что это такое украшение и это цена. Метод GetPrice () объекта топпинга вернет совокупную цену как пиццы, так и топпинга.

EDIT

вот код-пример объяснения выше.

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;
    }
}

Это простой пример динамического добавления нового поведения к существующему объекту или шаблону декоратора. Из-за природы динамических языков, таких как JavaScript, этот шаблон становится частью самого языка.

// 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...​​​​​​​​​​​​​​​

стоит отметить, что модель ввода-вывода Java основана на шаблоне декоратора. Наслоение этого читателя поверх этого читателя сверху of...is действительно реальный пример декоратора.

пример - сценарий - допустим, вы пишете модуль шифрования. Это шифрование может шифровать чистый файл с помощью стандарта шифрования DES - Data. Аналогично, в системе вы можете иметь шифрование в качестве стандарта шифрования AES-Advance. Кроме того, вы можете иметь комбинацию шифрования - сначала DES, затем AES. Или вы можете иметь сначала AES, а затем DES.

обсуждения - как вы будете обслуживать эту ситуацию? Вы не можете продолжать создавать объект таких комбинаций - например-AES и DES-всего 4 комбинации. Таким образом, вам нужно иметь 4 отдельных объекта, это станет сложным, поскольку тип шифрования будет увеличиваться.

решение-продолжайте создавать комбинации стека в зависимости от необходимости - во время выполнения. Еще одним преимуществом такого подхода к стеку является то, что вы можете легко его размотать.

вот решение - в C++.

во - первых, вам нужен базовый класс-фундаментальная единица стека. Вы можете думать как основание стека. В в данном примере это понятный файл. Давайте всегда следовать полиморфизму. Сначала создайте класс интерфейса этого фундаментального блока. Таким образом, вы можете реализовать его, как вы хотите. Кроме того, вам не нужно думать о зависимости, включая эту фундаментальную единицу.

вот класс интерфейса -

class IclearData
{
public:

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

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

теперь реализуем этот класс интерфейса -

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;
    }

};

теперь, давайте сделаем абстрактный класс декоратора, который может быть расширен для создания любой кухни - здесь вкус-это тип шифрования. Этот абстрактный класс декоратора связан с базовым классом. Таким образом, декоратор "является" своего рода классом интерфейса. Таким образом, вам нужно использовать наследование.

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;
}

теперь давайте сделаем конкретный класс декоратора - Тип шифрования-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;
    }

};

теперь предположим, что тип декоратора-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;
    }

};

давайте сделаем клиентский код для использования этого класса декоратора -

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;
}

вы увидите следующие результаты -

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

вот UML диаграмма-класс представление его. В случае, если вы хотите пропустить код и сосредоточиться на аспекте конструкции.

enter image description here

что такое шаблон дизайна декоратора в Java.

формальное определение шаблона декоратора из книги GoF (шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения, 1995, Pearson Education, Inc. Публикация как Pearson Addison Wesley) говорит, что вы можете,

" динамически присоединять дополнительные обязанности к объекту. Декораторы предоставьте гибкую альтернативу подклассам для расширения функциональности."

Допустим, у нас есть пицца и мы хотите украсить его начинками, такими как курица масала, лук и сыр Моцарелла. Давайте посмотрим, как это реализовать на Java ...

программа для демонстрации того, как реализовать шаблон дизайна декоратора в Java.

пицца.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());

}

}

шаблон декоратора помогает вам изменить или настроить функциональность вашего объекта, связав его с другими подобными подклассами этого объекта.

лучшим примером будет InputStream и OutputStream классы в java.io пакет

    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.

Я широко использовал шаблон декоратора в своей работе. Я сделал пост в моем блоге о том, как использовать его с журнала.

оформитель:

  1. добавить поведение объекта во время выполнения. Наследование является ключом к достижению этой функциональности, что является как преимуществом, так и недостатком этого шаблона.
  2. он усиливает поведение интерфейса.
  3. декоратора можно рассматривать как дегенерата композитные только с одним компонентом. Однако декоратор добавляет дополнительные обязанности - он не предназначен для объекта агрегация.
  4. класс декоратора объявляет отношение композиции к интерфейсу LCD (наименьший знаменатель класса), и этот элемент данных инициализируется в его конструкторе.
  5. декоратор предназначен для того, чтобы вы могли добавлять обязанности к объектам без подкласса

смотрите sourcemaking статьи для более подробной информации.

Декоратор (Аннотация) : это абстрактный класс/интерфейс, который реализует компонентный интерфейс. Он содержит интерфейс компонента. В отсутствие этого класса, вам нужно много подклассов ConcreteDecorators для различных комбинаций. Состав компонента уменьшает ненужные подклассы.

пример JDK:

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

посмотрите на ниже SE вопрос для UML диаграммы и примеров кода.

шаблон декоратора для IO

полезное статьи:

journaldev

Википедия

реальный пример слова шаблона декоратора: VendingMachineDecorator была объяснена @

когда использовать шаблон "декоратор"?

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

beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();

в приведенном выше примере чай или кофе ( напиток) был украшен сахаром и лимоном.

шаблон декоратора достигает одной цели динамическое добавление обязанностей к какому-либо объекту.

Java I / O Model основано на картине декоратора.

Java IO as decorator pattern

шаблон декоратора позволяет динамически добавлять поведение к объектам.

давайте возьмем пример, где вам нужно построить приложение, которое рассчитывает стоимость различных видов гамбургеров. Вам нужно обрабатывать различные варианты гамбургеров, такие как "большой" или "с сыром", каждый из которых имеет цену относительно основного гамбургера. Например, добавьте $ 10 для гамбургера с сыром, добавьте дополнительные $15 для большого гамбургера и т. д.

в этом случае у вас может возникнуть соблазн создайте подклассы для их обработки. Мы могли бы выразить это в Ruby как:

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

в приведенном выше примере класс BurgerWithCheese наследует от Burger и переопределяет метод price, чтобы добавить $15 к цене, определенной в суперклассе. Вы также создадите класс LargeBurger и определите цену относительно Burger. Но вам также нужно определить новый класс для комбинации "большой"и" с сыром".

теперь что произойдет, если нам нужно подавать "бургер с картошкой фри"? У нас уже есть 4 класса для обработки этих комбинаций, и нам нужно будет добавить еще 4 для обработки всей комбинации из 3 свойств - "большой", "с сыром" и "с картофелем фри". Теперь нам нужно 8 классов. Добавить еще одно свойство и нам понадобится 16. Это будет расти как 2^n.

вместо этого давайте попробуем определить BurgerDecorator, который принимает объект Burger:

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

в приведенном выше примере мы создали класс BurgerDecorator, от которого наследуется класс BurgerWithCheese. Мы можем также представляют" большой " вариант путем создания класса LargeBurger. Теперь мы могли бы определить большой гамбургер с сыром во время выполнения как:

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

помните, как использование наследования для добавления варианта "с картофелем фри" будет включать добавление еще 4 подклассов? С декораторами мы просто создадим один новый класс BurgerWithFries, чтобы обрабатывать новую вариацию и обрабатывать ее во время выполнения. Для каждого нового свойства потребуется просто больше декоратора, чтобы покрыть все перестановки.

PS. Это короткая версия статьи, о которой я писал Использование шаблона декоратора в Ruby, который вы можете прочитать, если вы хотите узнать более подробные примеры.

в Википедии есть пример украшения окна полосой прокрутки:

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

вот еще один очень "реальный" пример "члена команды, руководителя команды и менеджера", который иллюстрирует, что шаблон декоратора незаменим с простым наследованием:

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

Декоратор Дизайн Шаблон: Этот шаблон помогает изменять характеристики объекта во время выполнения. Он обеспечивает различные вкусы к объекту и дает гибкость, чтобы выбрать, какие ингредиенты мы хотим использовать в этом аромате.

Пример Из Реальной Жизни: Допустим, у вас есть основное место в салоне в полете. Теперь вы можете выбрать несколько удобств с сиденьем. Каждое удобство имеет свою собственную стоимость, связанную с ним. Теперь, если пользователь выбирает Wi-Fi и премиум-продукты питания, он / она будет взиматься плата за место + Wi-Fi + премиум питание.

enter image description here

в этом случае декоратор Дизайн Шаблон действительно может помочь нам. Посетите приведенную выше ссылку, чтобы узнать больше о шаблоне декоратора и реализации одного примера из реальной жизни.