Перейти к основному содержимому

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

· 3 мин. чтения

1. Обзор

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

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

2. Пример шаблона декоратора

Предположим, у нас есть объект «Рождественская елка», и мы хотим его украсить. Украшение не меняет самого объекта; просто в дополнение к елке мы добавляем некоторые элементы декора, такие как гирлянда, мишура, верхушка для елки, пузырьковые огни и т. д .:

./624232fd8536a79ec79f0dfab349770c.jpg

В этом сценарии мы будем следовать оригинальным соглашениям по дизайну и именованию Gang of Four. Во- первых, мы создадим интерфейс ChristmasTree и его реализацию:

public interface ChristmasTree {
String decorate();
}

Реализация этого интерфейса будет выглядеть так:

public class ChristmasTreeImpl implements ChristmasTree {

@Override
public String decorate() {
return "Christmas tree";
}
}

Теперь мы создадим абстрактный класс TreeDecorator для этого дерева. Этот декоратор реализует интерфейс ChristmasTree , а также содержит тот же объект. Реализованный метод из того же интерфейса просто вызовет метод decor() из нашего интерфейса:

public abstract class TreeDecorator implements ChristmasTree {
private ChristmasTree tree;

// standard constructors
@Override
public String decorate() {
return tree.decorate();
}
}

Теперь мы создадим декоративный элемент. Эти декораторы расширят наш абстрактный класс TreeDecorator и изменят его метод decor () в соответствии с нашими требованиями:

public class BubbleLights extends TreeDecorator {

public BubbleLights(ChristmasTree tree) {
super(tree);
}

public String decorate() {
return super.decorate() + decorateWithBubbleLights();
}

private String decorateWithBubbleLights() {
return " with Bubble Lights";
}
}

Для этого случая верно следующее:

@Test
public void whenDecoratorsInjectedAtRuntime_thenConfigSuccess() {
ChristmasTree tree1 = new Garland(new ChristmasTreeImpl());
assertEquals(tree1.decorate(),
"Christmas tree with Garland");

ChristmasTree tree2 = new BubbleLights(
new Garland(new Garland(new ChristmasTreeImpl())));
assertEquals(tree2.decorate(),
"Christmas tree with Garland with Garland with Bubble Lights");
}

Обратите внимание, что в первом объекте tree1 мы украшаем его только одной гирляндой , в то время как другой объект tree2 мы украшаем одним BubbleLights и двумя Garland . Этот шаблон дает нам возможность добавлять столько декораторов, сколько мы хотим во время выполнения.

4. Вывод

В этой статье мы рассмотрели шаблон проектирования декоратора. Это хороший выбор в следующих случаях:

  • Когда мы хотим добавить, улучшить или даже удалить поведение или состояние объектов
  • Когда мы просто хотим изменить функциональность одного объекта класса и оставить другие без изменений

Полный исходный код этого примера доступен на GitHub .