以前,我们使用桥模式更改了抽象对象的行为,并使用复合模式并委托了请求,从而为组件实现了类似树的结构。
装饰器模式允许将行为静态或动态地添加到单个对象,而不会影响同一类中其他对象的行为。
因此,请设想对我们的一种产品应用各种折扣的情况。
我们将从打折界面开始,指定打折动作。
package com.gkatzioura.design.structural.decorator;
import java.math.BigDecimal;
public interface Discount {
BigDecimal apply(BigDecimal originalPrice);
}
实施折价的对象将应用折价并返还折价。
我们要应用的折扣之一是针对新注册会员的特殊折扣。
新注册的会员首次下单可享受20%的折扣
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美元的优惠券折扣。
应用多次折扣非常常见,我们的系统必须支持此操作。 创建打折的包裹是很常见的,实际上这只是包裹的组合。
为此,我们将利用装饰器模式。
我们将创建折扣装饰器。
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美元的折扣,并且对原始价格要有折扣。
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%。
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);
}
}
如您所见,在参考用户折扣的情况下和在两年计划折扣的情况下,我们都没有更改新注册用户的原始折扣。 我们所做的是装饰原始折扣并通过考虑各种选择来返还折扣。
装饰器模式是关于
- 在运行时动态添加责任或将其从对象中动态删除。
- 无需子类化即可灵活扩展功能
因此,让我们付诸行动。
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上找到源代码。
翻译自: https://www.javacodegeeks.com/2018/08/structural-design-decorator-pattern.html