Статьи

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

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

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

Диаграмма UML:

Давайте начнем с рассмотрения UML-представления шаблона декоратора:

Класс ConcreteComponent — это класс, для которого мы хотели бы добавить дополнительные поведения во время выполнения. ConcreteDecorator1 , ConcreteDecorator2 ,… являются классами декоратора, которые содержат логику для украшения данного Компонента .

Обратите внимание, что абстрактный класс Decorator имеет Component. Другими словами, он объединяет любой другой тип компонента, который позволяет нам размещать компоненты один поверх другого.

Более того, оба класса ConcreteComponent и Decorator реализуют общий интерфейс — Component .

Пример реализации:

Допустим, мы продаем подарок. После того, как пользователь выбирает подарочный товар, может быть несколько способов просто украсить его, скажем, красной или синей лентой, фиолетовой или зеленой подарочной упаковкой и т. Д.

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

Итак, давайте создадим наш интерфейс GiftComponent :

1
2
3
public interface GiftComponent {
    void pack();
}

Также, давайте напишем наш класс GiftItem, который является конкретной реализацией GiftComponent :

1
2
3
4
5
6
public class GiftItem implements GiftComponent {
  
    public void pack() {
        System.out.println("Putting it in a box");
    }
}

Реализация абстрактного декоратора:

Теперь, когда у нас есть GiftItem, который мы хотим украсить, давайте определим наш абстрактный класс GiftDecorator :

01
02
03
04
05
06
07
08
09
10
11
public abstract AbstractGiftDecorator implements GiftComponent {
    protected GiftComponent gift;
  
    public AbstractGiftDecorator(GiftComponent gift) {
        this.gift = gift;
    }
     
    public void pack() {
        this.gift.pack();
    }
}

Декоратор подарков имеет единственный экземпляр компонента подарка. Это позволяет накладывать декораторы друг на друга.

Создание нескольких декораторов:

Наконец, мы можем создать столько пользовательских декораторов, сколько захотим.

Давайте создадим несколько подарочных упаковок:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PurpleWrapper extends AbstractGiftDecorator {
  
    public PurpleWrapper(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Purple wrapper");
    }
}
  
public class RedWrapper extends AbstractGiftDecorator {
  
    public RedWrapper(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Red wrapper");
    }
}

И несколько видов лент для дальнейшей отделки:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class BlueRibbon extends AbstractDecorator {
  
    public BlueRibbon(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Blue ribbon");
    }
}
  
public class PinkRibbon extends AbstractDecorator {
  
    public PinkRibbon(GiftComponent gift) {
        super(gift);
    }
  
    public void pack() {
        super.pack();
        System.out.println("Pink Ribbon");
    }
}

Тестирование нашей реализации:

Давайте теперь протестируем нашу реализацию, чтобы увидеть, что происходит:

1
2
3
4
5
6
7
// client code
GiftComponent gift = new GiftItem();
GiftComponent giftWithPurpleWrapper = new PurpleWrapper(gift);
GiftComponent giftWithPurpleWrapperAndPinkRibbon =
  new PinkRibbon(giftWithPurpleWrapper);
  
giftWithPurpleWrapperAndPinkRibbon.pack();

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

1
2
3
Putting it in a box
Purple Wrapper
Pink Ribbon

Вывод:

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

Кроме того, он придерживается принципа единой ответственности, который гласит, что каждый класс должен делать только одно. Такие классы, как java.io.BufferedReader, java.io.FileReader , разрабатываются с использованием шаблона проектирования декоратора .

Опубликовано на Java Code Geeks с разрешения Шубхры Шриваставы, партнера нашей программы JCG . Посмотрите оригинальную статью здесь: Шаблон дизайна Decorator на Java

Мнения, высказанные участниками Java Code Geeks, являются их собственными.