Зрозумійте "візерунок декораторів" на прикладі реального світу


167

Я вивчав узор декораторів, як це зафіксовано в GOF .

Будь ласка, допоможіть мені зрозуміти шаблон декору . Чи може хтось навести приклад використання того, де це корисно в реальному світі?


8
Тут ви можете знайти деякі приклади RealWorld в Java API: stackoverflow.com/questions/1673841 / ...
BalusC

Стаття, яка показує переваги візерунка декораторів з простими прикладами: dzone.com/articles/is-inheritance-dead
nbilal

Відповіді:


226

Шаблон декоратора досягає єдиної мети - динамічно додавати обов'язки до будь-якого об’єкта.

Розглянемо випадок піцерії. У магазині піци вони продаватимуть кілька різновидів піци, а також додадуть начинки в меню. А тепер уявіть собі ситуацію, коли піца повинна забезпечити ціни за кожну комбінацію піци та начинки. Навіть якщо є чотири основні піци та 8 різних начинок, додаток зійде з розуму, підтримуючи всі ці конкретні комбінації піци та начинки.

Тут виходить візерунок декоратора.

Відповідно до візерунка декораторів, ви будете реалізовувати начинки, як декоратори, а піци будуть прикрашені тими декораторами начинки. Практично кожен замовник бажає начинки за своїм бажанням, а остаточна сума рахунку буде складатися з базових піц та додатково замовлених начинок. Кожен декоратор-топінг знав би про піци, які вона прикрашає, і це ціна. Метод GetPrice () об'єкта Topping поверне сукупну ціну як піци, так і начинки.

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

104
Не подобається цей зразок один біт. Можливо, це все-таки приклад. Основне питання, яке я маю з цим щодо OOD, - це те, що начинка - це не піца . Запитуючи ціну на піцу, яку вона застосовує, просто не сидіти зі мною. Хоча це дуже продуманий і детальний приклад, тож я не хочу вас з цим стукати.
Том Ш

39
@TomW Я думаю, що частиною проблеми є називання. Усі класи "Топінг" повинні називатися "PizzaWith <Topping>". Наприклад, "PizzaWithMushrooms".
Josh Noe

2
На мою думку, декораторів найкраще використовувати максимально рівномірно. Під цим я маю на увазі якомога менше "декораторів, які обгортають декораторів". Тож, мабуть, цей приклад не найвдаліший. Але це досить ретельно, що приємно.
thekingoftruth

17
З іншого боку, це навіть не близько до "реального світу". У реальному світі не слід перекомпілювати кожен раз, коли потрібно додавати нове додавання до меню (або змінювати ціну). Начинки (як правило) зберігаються в базі даних і, таким чином, роблять вищезгаданий приклад марним.
Stelios Adamantidis

4
^ Це. Я думаю, що це те, що мене турбує весь час під час вивчення цієї картини. Якби я була програмною компанією і писала програмне забезпечення для піцерії, я б не хотіла щоразу переписувати та відправляти повторно. Я хотів би додати рядок у таблицю в бекенде або щось, що легко переймається їх вимогою. Добре сказано, @Stelios Adamantidis. Я здогадуюсь, що шаблони найбільшої сили, хоча б тоді змінювали сторонні класи.
Canucklesandwich

33

Це простий приклад додавання нової поведінки до вже існуючого об'єкта динамічно або шаблону «Декоратор». Завдяки природі динамічних мов, таких як 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
Я не думаю, що тут застосовується поняття «Декоративний візерунок». Насправді це зовсім не зразок !. Так, ви додаєте новий метод під час виконання. І, ймовірно, всередині switchабо простого if, ви зможете стверджувати, що це чудовий приклад динамічного додавання поведінки до класу. Але нам потрібно щонайменше два класи, щоб визначити декоратор та декоровані об’єкти за цим шаблоном.
Іман

1
@ Zich Я розумію, що в моєму прикладі немає декоратора, але це легко виправити, додавши функцію, яка виконує функції декоратора. Але є прикрашений предмет на моєму прикладі. Чи де-небудь говорить шаблон, що вам потрібно два класи конкретно?
Анураг

18

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


Чи є ще інші приклади в реальних публічних API? Це єдиний, кого я знаю.
Йосія Йодер

Здається, що у всіх функціях обгортки в природі є якась побудована модель декору, це я вважаю, що це?
Харві Лін

Хороший приклад !!
nagendra547

8

Приклад - Сценарій. Скажімо, ви пишете модуль шифрування. Це шифрування може зашифрувати очищений файл, використовуючи DES - стандарт шифрування даних. Так само в системі ви можете мати шифрування як AES - стандарт попереднього шифрування. Також у вас може бути комбінація шифрування - Спочатку 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";

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

Шаблон декоратора допомагає вам змінити або налаштувати функціональність вашого об'єкта, з'єднавшись з іншими подібними підкласами цього об’єкта.

Найкращим прикладом можуть бути класи 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.

Офіційне визначення візерунка «Декоратор» з книги GoF (Шаблони дизайну: Елементи багаторазового використання об’єктно-орієнтованого програмного забезпечення, 1995, Pearson Education, Inc. Публікація як Pearson Addison Wesley) говорить, що ви можете,

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

Скажімо, у нас є Піца, і ми хочемо прикрасити її начинками, такими як Куряча Масала, Цибуля та Сир Моцарелла. Давайте подивимося, як це реалізувати на Java ...

Програма для демонстрації того, як реалізувати шаблон дизайну декораторів на 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

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


Мені не подобається, що ти просто кинув посилання як відповідь. Але ваша стаття в блозі настільки корисна, що мені просто довелося подати заяву :). Тепер я справді це розумію. Усі йдуть з піцами, а ви - з ідеальним прикладом.
Ніклас Рааб

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, щоб обробити всі поєднання трьох властивостей - "великий", "з сиром" і "з фрі". Зараз нам потрібно 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 , яку ви можете прочитати, якщо хочете дізнатись більш детальні приклади.


2

Декоратор:

  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

Корисні статті:

журналдев

Вікіпедія

Справжній приклад слова візерунка декоратора: 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 I / O заснована на шаблоні декораторів.

Java IO як візерунок декоратора


1

У Вікіпедії є приклад про декорування вікна смугою прокрутки:

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

Ось ще один дуже "реальний" приклад "Член команди, керівник команди та менеджер", який ілюструє, що модель декоратора незамінна простим успадкуванням:

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


Це посилання Зішана Білала - чудовий приклад, який я бачив
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до фонових послуг. Такий підхід мені не здався вдалим. На думку мене, перевірка ліцензії та інша логіка були ортогональними один для одного.

Тож на допомогу приходить Pattern Decorator і тут починається рефакторинг з 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");

Винос

  • Згуртованість коду покращилася
  • Тестування блоків стало простішим, оскільки не потрібно знущатися над ліцензуванням під час тестування ServiceSupport
  • Не потрібно обходити ліцензування будь-якими спеціальними чеками на фонові послуги
  • Правильний розподіл обов'язків

1

Візьмемо для прикладу PubG. Гвинтівки штурму найкраще спрацьовують із 4-кратним збільшенням, і, поки ми на ньому, нам також знадобляться компенсатор і супресор. Це зменшить віддалення та зменшить звук стрільби, а також відлуння. Нам потрібно буде реалізувати цю функцію там, де ми дозволимо гравцям придбати улюблену зброю та їхні аксесуари. Гравці можуть придбати пістолет або якийсь аксесуар або весь аксесуар, і за них платять відповідно.

Давайте подивимось, як тут застосовується візерунок декораторів:

Припустимо, хтось хоче придбати SCAR-L з усіма трьома згаданими вище аксесуарами.

  1. Візьміть предмет SCAR-L
  2. Прикрасьте (або додайте) SCAR-L об'єктом 4-кратного масштабування
  3. Прикрасьте SCAR-L супресорним предметом
  4. Прикрасьте SCAR-L предметом компресора
  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

Шаблон дизайну декораторів : Цей шаблон допомагає змінити характеристики об'єкта під час виконання. Він надає об'єкту різні ароматизатори та надає гнучкість у виборі, які інгредієнти ми хочемо використати для цього аромату.

Приклад із реального життя: Скажімо, у вас є основне сидіння в кабіні під час польоту. Тепер вам дозволяється вибирати кілька зручностей із сидінням. Кожна цінність пов'язана з нею. Тепер, якщо користувач вибирає Wi-Fi та преміум-продукти, йому / їй платять за сидіння + wifi + преміум-їжу.

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.