Шаблон Decorator динамически изменяет функциональность объекта во время выполнения, не влияя на существующую функциональность объектов.
Ключевые варианты использования:
- Динамически добавлять дополнительные функции / обязанности
- Динамическое удаление функций / обязанностей
- Избегайте слишком большого подкласса , чтобы добавить дополнительные обязанности.
Недостатки:
- Чрезмерное использование принципа Открыто-закрыто (Открыто для расширения и Закрыто для модификации). Используйте эту функцию с осторожностью там, где код наименее вероятно изменился.
- Слишком много маленьких классов и добавит накладных расходов на обслуживание .
Пример из реальной жизни: Вычислите цену напитка, который может содержать несколько вкусов.
abstract class Beverage {
protected String name;
protected int price;
public Beverage(){
}
public Beverage(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
protected void setPrice(int price){
this.price = price;
}
protected int getPrice(){
return price;
}
protected abstract void decorateBeverage();
}
class Tea extends Beverage{
public Tea(String name){
super(name);
setPrice(10);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
class Coffee extends Beverage{
public Coffee(String name){
super(name);
setPrice(15);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
abstract class BeverageDecorator extends Beverage {
protected Beverage beverage;
public BeverageDecorator(Beverage beverage){
this.beverage = beverage;
setName(beverage.getName()+"+"+getDecoratedName());
setPrice(beverage.getPrice()+getIncrementPrice());
}
public void decorateBeverage(){
beverage.decorateBeverage();
System.out.println("Cost of:"+getName()+":"+getPrice());
}
public abstract int getIncrementPrice();
public abstract String getDecoratedName();
}
class SugarDecorator extends BeverageDecorator{
public SugarDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateSugar();
}
public void decorateSugar(){
System.out.println("Added Sugar to:"+beverage.getName());
}
public int getIncrementPrice(){
return 5;
}
public String getDecoratedName(){
return "Sugar";
}
}
class LemonDecorator extends BeverageDecorator{
public LemonDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateLemon();
}
public void decorateLemon(){
System.out.println("Added Lemon to:"+beverage.getName());
}
public int getIncrementPrice(){
return 3;
}
public String getDecoratedName(){
return "Lemon";
}
}
public class VendingMachineDecorator {
public static void main(String args[]){
Beverage beverage = new SugarDecorator(new LemonDecorator(new Tea("Assam Tea")));
beverage.decorateBeverage();
beverage = new SugarDecorator(new LemonDecorator(new Coffee("Cappuccino")));
beverage.decorateBeverage();
}
}
выход:
Cost of:Assam Tea:10
Cost of:Assam Tea+Lemon:13
Added Lemon to:Assam Tea
Cost of:Assam Tea+Lemon+Sugar:18
Added Sugar to:Assam Tea+Lemon
Cost of:Cappuccino:15
Cost of:Cappuccino+Lemon:18
Added Lemon to:Cappuccino
Cost of:Cappuccino+Lemon+Sugar:23
Added Sugar to:Cappuccino+Lemon
В этом примере вычисляется стоимость напитка в торговом автомате после добавления в напиток множества вкусов.
В приведенном выше примере:
Стоимость чая = 10, Лимона = 3 и Сахара = 5. Если вы делаете Сахар + Лимон + Чай, это стоит 18.
Стоимость кофе = 15, лимона = 3 и сахара = 5. Если вы производите сахар + лимон + кофе, это стоит 23
Благодаря использованию одного и того же декоратора для обоих напитков (чай и кофе) количество подклассов было сокращено. В отсутствие шаблона Decorator у вас должны быть разные подклассы для разных комбинаций.
Комбинации будут такими:
SugarLemonTea
SugarTea
LemonTea
SugarLemonCapaccuino
SugarCapaccuino
LemonCapaccuino
и т.д..
При использовании одного и того же Декоратора для обоих напитков количество подклассов было сокращено. Это возможно благодаря составу , а не наследованию концепции, используемой в этом шаблоне.
Вопрос по теме SE:
Шаблон декоратора для ввода / вывода
Полезные ссылки:
Дизайн-шаблоны-декоратор от dzone
декоратор с помощью sourcemaking
oodesign артикул