Ранее мы изменили поведение наших абстрактных объектов, используя шаблон моста , и реализовали древовидную структуру для наших компонентов, используя составной шаблон и делегируя запросы.
Шаблон декоратора позволяет добавлять поведение к отдельному объекту, статически или динамически, без влияния на поведение других объектов того же класса.
Итак, представьте сценарий применения различных скидок к одному из наших продуктов.
Мы начнем с интерфейса скидок, чтобы указать действие скидки.
|
1
2
3
4
5
6
7
8
9
|
package com.gkatzioura.design.structural.decorator;import java.math.BigDecimal;public interface Discount { BigDecimal apply(BigDecimal originalPrice); } |
Объект, который реализует скидку, применяет скидку и возвращает скидку.
Одна из скидок, которую мы хотим применить, — это специальная скидка для вновь зарегистрированных пользователей.
У новых зарегистрированных участников будет скидка 20% на первый заказ
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
package com.gkatzioura.design.structural.decorator;import java.math.BigDecimal;public class NewlyRegisteredDiscount implements Discount { public static final BigDecimal SEVENTY_FIVE = new BigDecimal(75); public static final BigDecimal ONE_HUNDRED = new BigDecimal(100); @Override public BigDecimal apply(BigDecimal originalPrice) { return originalPrice.multiply(SEVENTY_FIVE).divide(ONE_HUNDRED); }} |
Как вы уже испытывали, иногда применяется более одной скидки.
Наша система также предоставляет нашим клиентам купонные скидки от 5 долларов.
Очень удобно применять несколько скидок, и наши системы должны поддерживать это действие. Обычно создаются пакеты скидок, которые на самом деле являются просто набором пакетов.
Для этого мы будем использовать шаблон декоратора.
Мы создадим декоратор скидок.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
package com.gkatzioura.design.structural.decorator;import java.math.BigDecimal;public class DiscountDecorator implements Discount { protected Discount discount; public DiscountDecorator(Discount discount) { this.discount = discount; } @Override public BigDecimal apply(BigDecimal originalPrice) { return discount.apply(originalPrice); }} |
Поэтому мы хотим получить скидку при первой покупке и скидку в 5 долларов для новых пользователей, на которые ссылаются другие пользователи.
Мы будем называть эту скидку скидкой для «указанного пользователя».
Цель состоит в том, чтобы получить 5 долларов и применить скидку к первоначальной цене.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.gkatzioura.design.structural.decorator;import java.math.BigDecimal;public class ReferencedUserDiscount extends DiscountDecorator { public static final BigDecimal FIVE = new BigDecimal(5); public ReferencedUserDiscount(Discount discount) { super(discount); } @Override public BigDecimal apply(BigDecimal originalPrice) { BigDecimal discountedPrice = super.apply(originalPrice); if(discountedPrice.compareTo(FIVE)<=0) { return discountedPrice; } return discountedPrice.subtract(FIVE); }} |
Представьте себе сейчас сценарий скидки лояльности. Мы хотим двухлетний план для наших пользователей со скидкой 5% на каждый их заказ.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
package com.gkatzioura.design.structural.decorator;import java.math.BigDecimal;public class TwoYearPlanDiscount extends DiscountDecorator { public static final BigDecimal NINETY_NINE = new BigDecimal(95); public static final BigDecimal ONE_HUNDRED = new BigDecimal(100); public TwoYearPlanDiscount(Discount discount) { super(discount); } @Override public BigDecimal apply(BigDecimal originalPrice) { return super.apply(originalPrice).multiply(NINETY_NINE).divide(ONE_HUNDRED); }} |
Как вы можете видеть как в случае скидок для указанных пользователей, так и в случае двухлетней скидки, мы не изменили нашу первоначальную скидку для наших новых зарегистрированных пользователей. То, что мы сделали, это украсили оригинальную скидку и вернули скидку, учитывая различные варианты.
Шаблон декоратора
- Добавьте обязанности или удалите их из объекта динамически во время выполнения.
- Расширьте функциональность гибким способом без создания подклассов
Итак, давайте воплотим наш план в жизнь.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
package com.gkatzioura.design.structural.decorator;import java.math.BigDecimal;public class DecoratorScenario { public static void main(String args[]) { NewlyRegisteredDiscount newlyRegisteredDiscount = new NewlyRegisteredDiscount(); ReferencedUserDiscount referencedUserDiscount = new ReferencedUserDiscount(newlyRegisteredDiscount); TwoYearPlanDiscount twoYearPlanDiscount = new TwoYearPlanDiscount(referencedUserDiscount); BigDecimal discountPrice = twoYearPlanDiscount.apply(new BigDecimal(100)); }} |
Наши новые зарегистрированные пользователи будут иметь три вида скидок.
Вы можете найти исходный код на github .
| Опубликовано на Java Code Geeks с разрешения Эммануила Гкациоураса, партнера нашей программы JCG. См. Оригинальную статью здесь: Структурные Проектные Образцы: Образец Декоратора
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |