Подтвердить что ты не робот

Зачем нам декоратор в шаблоне дизайна декоратора?

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

Я не понимаю, почему мы должны создавать класс декоратора вместо использования экземпляра A?

4b9b3361

Ответ 1

Шаблон декоратора используется для динамического добавления возможностей объектов (то есть во время выполнения). Обычно объект будет иметь свои возможности, если вы напишете класс. Но важным моментом является то, что функциональность объекта расширяется таким образом, который прозрачен для клиента объекта, потому что он реализует тот же интерфейс, что и исходный объект делегирует ответственность за украшенный объект.

Шаблон декоратора работает в сценариях, где есть много дополнительных функций, которые могут иметь объекты. Без шаблона декоратора вам придется создать другой класс для каждой конфигурации объекта-опции. Один из примеров, который очень полезен, - это книга Head First Design Patterns книги О'Рейли. Он использует пример кафе, который звучит так же, как StarBucks.

Итак, у вас есть основной кофе с таким методом, как стоимость.

public double cost(){
     return 3.45;
}

Затем клиент может добавить крем, который стоит 0,35, поэтому теперь вы создаете класс CoffeeCream со стоимостью:

public double cost(){
    return 3.80;
}

Тогда клиенту может понадобиться мокка, которая стоит 0.5, и они могут захотеть мокки с кремом или моккой без крема. Таким образом, вы создаете классы CoffeeMochaCream и CoffeeMocha. Затем клиент хочет использовать двойной крем, поэтому вы создаете класс CoffeeCreamCream... и т.д. В результате вы получаете классный взрыв. Извините, пожалуйста, использованный пример. Это немного поздно, и я знаю, что это тривиально, но это выражает точку.

Вместо этого вы можете создать абстрактный элемент Item с абстрактным методом затрат:

public abstract class Item{
    public abstract double cost();
}

И вы можете создать конкретный класс кофе, который расширяет Item:

public class Coffee extends Item{
    public double cost(){
       return 3.45;
    }
}

Затем вы создаете CoffeeDecorator, которые расширяют один и тот же интерфейс и содержат элемент.

public abstract class CoffeeDecorator extends Item{
     private Item item;
     ...
}

Затем вы можете создать конкретные декораторы для каждой опции:

public class Mocha extends CoffeeDecorator{

   public double cost(){
     return item.cost() + 0.5;
   }

}

Обратите внимание, что декоратору не важно, какой тип объекта он обертывает, пока он является Item? Он использует cost() объекта item и просто добавляет свои собственные затраты.

public class Cream extends CoffeeDecorator{

   public double cost(){
     return item.cost() + 0.35;
   }

}

Теперь возможно большое количество конфигураций с этими несколькими классами: например.

 Item drink = new Cream(new Mocha(new Coffee))); //Mocha with cream

или

 Item drink = new Cream(new Mocha(new Cream(new Coffee))));//Mocha with double cream

И так далее.

Ответ 2

Я не могу объяснить это лучше, чем wikipedia.

Ответ 3

Кстати, если вы только начинаете с шаблонов, книга Head First Design Patterns феноменальна. Это действительно упрощает переосмысление понятий и позволяет сопоставлять и сравнивать аналогичные шаблоны таким образом, что это смешно легко понять.

Ответ 4

На некоторых языках (например, Ruby или JavaScript) вы можете просто добавить новые функции в экземпляр A. Я заметил, что на ваш вопрос помечена Java, поэтому я предполагаю, что вы спрашиваете, почему вы не можете сделать это на Java. Причина в том, что Java статически типизирована. Экземпляр A может только когда-либо иметь методы, которые класс A определяет или наследует. Поэтому, если вы хотите во время выполнения предоставить экземпляр A метод, который A не определяет, то этот новый метод должен быть определен в другом классе.