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

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

1. обзор

A Decorator pattern can be used to attach additional responsibilities to an object either statically or dynamically. Декоратор предоставляет улучшенный интерфейс для исходного объекта.

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

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

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

image

For this scenario, we’ll follow the original Gang of Four design and naming conventions. Сначала мы создадим интерфейсChristmasTree и его реализацию:

public interface ChristmasTree {
    String decorate();
}

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

public class ChristmasTreeImpl implements ChristmasTree {

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

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

public abstract class TreeDecorator implements ChristmasTree {
    private ChristmasTree tree;

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

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

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 мы украшаем его только однимGarland, тогда как другой объектtree2 мы украшаем однимBubbleLights и двумяGarlandsс. Этот шаблон дает нам такую ​​гибкость, чтобы добавлять столько декораторов, сколько мы хотим во время выполнения.

4. Заключение

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

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

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

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