Поймите «Шаблон декоратора» на примере реального мира


167

Я изучал шаблон декоратора как документировано в GOF .

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


8
Вы можете найти здесь некоторые примеры из реального мира в Java API: stackoverflow.com/questions/1673841/…
BalusC

Статья, которая показывает преимущества шаблона декоратора на простых примерах: dzone.com/articles/is-inheritance-dead
nbilal

Ответы:


226

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

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

Вот идет образец декоратора.

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

РЕДАКТИРОВАТЬ

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

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

104
Не нравится этот шаблон один бит. Может быть, это пример, хотя. Основная проблема, которую я имею с точки зрения OOD, состоит в том, что начинка не пицца . Запрашиваемая цена за пиццу, к которой она применяется, просто не подходит мне. Это очень вдумчивый и подробный пример, поэтому я не хочу вас за это стучать.
Том W

39
@ TomW Я думаю, что частью проблемы является наименование. Все классы «Topping» должны называться «PizzaWith <Topping>». Например, «Пицца с грибами».
Джош Ноу

2
На мой взгляд, декораторы лучше всего использовать как можно более категорически. Под этим я подразумеваю как можно меньше «декораторов, оборачивающих декораторы». Так что, возможно, этот пример не самый удачный. Но это довольно тщательно, что приятно.
thekingoftruth

17
С другой стороны, это даже не близко к «реальному миру». В реальном мире вам не следует перекомпилировать каждый раз, когда вам нужно добавить новый топпинг в меню (или изменить цену). Начинки (обычно) хранятся в базе данных и, таким образом, делают приведенный выше пример бесполезным.
Стелиос Адамантидис

4
^ Это. Я думаю, что это то, что беспокоило меня все время при изучении этого паттерна. Если бы я был компанией-разработчиком программного обеспечения и писал программное обеспечение для магазина пиццы, мне бы не пришлось каждый раз перекомпилировать и перезаписывать. Я хотел бы добавить строку в таблицу в серверной части или что-то, что легко позаботится об их требовании. Хорошо сказано, @Stelios Adamantidis. Я предполагаю, что самой сильной стороной паттернов будет модификация сторонних классов.
Canucklesandwich

33

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

// Person object that we will be decorating with logging capability
var person = {
  name: "Foo",
  city: "Bar"
};

// Function that serves as a decorator and dynamically adds the log method to a given object
function MakeLoggable(object) {
  object.log = function(property) {
    console.log(this[property]);
  }
}

// Person is given the dynamic responsibility here
MakeLoggable(person);

// Using the newly added functionality
person.log('name');


Просто и точно! Отличный пример!
nagendra547

1
Я не думаю, что концепция Decorator Pattern применима здесь. На самом деле это не шаблон вообще! Да, вы добавляете новый метод во время выполнения. И, вероятно, внутри switchили просто if, вы могли бы утверждать, что это отличный пример динамического добавления поведения в класс. НО, нам нужно как минимум два класса, чтобы определить декоратор и декорированные объекты в этом шаблоне.
Иман

1
@Zich Я понимаю, что в моем примере нет декоратора, но это легко исправить, добавив функцию, которая служит декоратором. Но в моем примере есть украшенный предмет. Шаблон говорит где-нибудь, что вам нужно два класса специально?
Анураг

18

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


Есть ли другие примеры в реальных публичных API? Это единственный, кого я знаю.
Иосия Йодер

Кажется, что все функции-обертки в природе имеют своего рода встроенный шаблон декоратора, я так думаю?
Харви Лин

Хороший пример !!
nagendra547

8

Пример - Сценарий. Допустим, вы пишете модуль шифрования. Это шифрование может зашифровать чистый файл, используя DES - стандарт шифрования данных. Аналогично, в системе вы можете использовать шифрование как стандарт шифрования 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 - Классовое представление этого. В случае, если вы хотите пропустить код и сосредоточиться на аспекте дизайна.

введите описание изображения здесь


1
не более ли подходит пример strategy pattern?
exexzian

@exexzian Да, мои ученики постоянно предлагают мне список стратегий для этого типа проблемы, и мне кажется, что это самое чистое решение.
Джозия Йодер

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

4

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

Лучший пример - классы 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.

В этом случае вызывающая цепочка начинается с ObjectOutputStream, затем проходит до класса File, затем класс File возвращает значение, затем три других подкласса складывают их все и, наконец, значение метода ObjectOutputStream возвращает его, это правильно?
Харви Лин

3

Что такое шаблон оформления декоратора в Java.

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

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

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

Программа для демонстрации того, как реализовать Pattern Design Decorator в Java.

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

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


Мне не нравится, что вы просто бросили ссылку в качестве ответа. Но твоя статья в блоге настолько полезна, что мне просто нужно было поднять голос :). Теперь я действительно понимаю это. Все идут с пиццей, а вы с прекрасным примером.
Никлас Рааб

2

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

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

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

class Burger
  def price
    50
  end
end

class BurgerWithCheese < Burger
  def price
    super + 15
  end
end

В приведенном выше примере класс BurgerWithCheese наследуется от Burger и переопределяет метод цены, добавляя $ 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. Это краткая версия статьи об использовании шаблона Decorator в Ruby , которую я написал , которую вы можете прочитать, если хотите найти более подробные примеры.


2

Decorator:

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

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

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

Пример 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-диаграммы и примеров кода.

Декоратор Pattern для IO

Полезные статьи:

journaldev

википедия

Пример настоящего слова шаблона Decorator: VendingMachineDecorator @

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

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

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

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


2

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

Модель ввода / вывода Java основана на шаблоне декоратора.

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


1

В Википедии есть пример оформления окна с помощью полосы прокрутки:

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

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

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


Эта ссылка на Zishan Bilal великолепна - лучший пример, который я видел
stonedauwg

1

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

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

Все сервисы имеют общий интерфейс

interface Service {
  String serviceId();
  void init() throws Exception;
  void start() throws Exception;
  void stop() throws Exception;
}

Предварительный рефакторинг

abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId, LicenseManager licenseManager) {
    // assign instance variables
  }

  @Override
  public void init() throws Exception {
    if (!licenseManager.isLicenseValid(serviceId)) {
       throw new Exception("License not valid for service");
    }
    // Service initialization logic
  }
}

Если вы внимательно наблюдаете, ServiceSupportзависит от LicenseManager. Но почему это должно зависеть отLicenseManager ? Что, если нам нужен фоновый сервис, который не должен проверять информацию о лицензии. В сложившейся ситуации нам придется как-то тренироваться, LicenseManagerчтобы вернутьсяtrue за справочными услугами. Этот подход мне не показался удачным. По моему мнению проверка лицензии и другая логика были ортогональны друг другу.

Так на помощь приходит Decorator Pattern и здесь начинается рефакторинг с TDD.

Постфакторинг

class LicensedService implements Service {
  private Service service;
  public LicensedService(LicenseManager licenseManager, Service service) {
    this.service = service;
  }

  @Override
  public void init() {
    if (!licenseManager.isLicenseValid(service.serviceId())) {
      throw new Exception("License is invalid for service " + service.serviceId());
    }
    // Delegate init to decorated service
    service.init();
  }

  // override other methods according to requirement
}

// Not concerned with licensing any more :)
abstract class ServiceSupport implements Service {
  public ServiceSupport(String serviceId) {
    // assign variables
  }

  @Override
  public void init() {
    // Service initialization logic
  }
}

// The services which need license protection can be decorated with a Licensed service
Service aLicensedService = new LicensedService(new Service1("Service1"), licenseManager);
// Services which don't need license can be created without one and there is no need to pass license related information
Service aBackgroundService = new BackgroundService1("BG-1");

Takeaways

  • Сплоченность кода стала лучше
  • Модульное тестирование стало проще, так как не нужно проверять лицензирование при тестировании ServiceSupport
  • Не нужно обходить лицензирование какими-либо специальными проверками фоновых сервисов
  • Правильное разделение обязанностей

1

Давайте возьмем пример PubG. Штурмовые винтовки лучше всего работают с 4-кратным зумом, и пока мы на нем, нам также понадобятся компенсатор и подавитель. Это уменьшит отдачу и уменьшит звук стрельбы, а также эхо. Нам нужно будет реализовать эту функцию, где мы позволим игрокам покупать их любимые ружья и аксессуары. Игроки могут купить пистолет или часть аксессуара или весь аксессуар, и с них будет взиматься соответствующая плата.

Давайте посмотрим, как шаблон декоратора применяется здесь:

Предположим, кто-то хочет купить SCAR-L со всеми тремя аксессуарами, упомянутыми выше.

  1. Возьмите предмет SCAR-L
  2. Украсьте (или добавьте) СКАР-Л с 4-кратным увеличением
  3. Украсьте СКАР-Л объектом-подавителем
  4. Украсьте СКАР-Л компрессором
  5. Вызовите метод стоимости и позвольте каждому делегату объекта добавить стоимость, используя метод стоимости аксессуаров.

Это приведет к такой диаграмме классов:

Шаблон декоратора на работе

Теперь у нас могут быть такие классы:

public abstract class Gun {     
    private Double cost;    
    public Double getCost() {           
        return cost;        
       }    
    }

public abstract class GunAccessories extends Gun {  }

public class Scarl extends Gun {    
    public Scarl() {            
        cost = 100;
        }   
     }

public class Suppressor extends GunAccessories {        
    Gun gun;        
    public Suppressor(Gun gun) {            
    cost = 5;           
    this.gun = gun;     
    }               
    public double getCost(){            
        return cost + gun.getCost();
    }
}

public class GunShop{   
    public static void main(String args[]){         
    Gun scarl = new Scarl();                
    scarl = new Supressor(scarl);
    System.out.println("Price is "+scarl.getCost());
    }      
}

Мы также можем добавить другие аксессуары и украсить наш пистолет.

Ссылка:

https://nulpointerexception.com/2019/05/05/a-beginner-guide-to-decorator-pattern/


0

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

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

введите описание изображения здесь

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.