目录
1.先建立订单和商品的属性类:主订单+详细订单+商品+促销类型+优惠券+红包
干货分享,感谢您的阅读!
一、装饰器模式的概念及怎么用?
1.基本概念和功能
装饰器模式能够实现从一个对象的外部来给对象添加功能,有非常灵活的扩展性,可以在对原来的代码毫无修改的前提下,为对象添加新功能。除此之外,装饰器模式还能够实现对象的动态组合,借此我们可以很灵活地给动态组合的对象,匹配所需要的功能。
2.结构图分析
- Component为统一接口,也是装饰类和被装饰类的基本类型。
- ConcreteComponent为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类。
- Decorator是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。而Decorator本身,通常采用默认实现,他的存在仅仅是一个声明:我要生产出一些用于装饰的子类了。而其子类才是赋有具体装饰效果的装饰产品类。
- ConcreteDecorator是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent,从而对其进行装饰。
3.举例分析
假设现在有这样一个需求,让你设计一个装修功能,用户可以动态选择不同的装修功能来装饰自己的房子。例如,水电装修、天花板以及粉刷墙等属于基本功能,而设计窗帘装饰窗户、设计吊顶装饰房顶等未必是所有用户都需要的,这些功能则需要实现动态添加。还有就是一旦有新的装修功能,我们也可以实现动态添加。
采用装饰器模式可以很好的解决以上问题。
二、装饰器模式的基本用法
基于装饰器模式实现的装修功能的代码结构简洁易读,业务逻辑也非常清晰,并且如果我们需要扩展新的装修功能,只需要新增一个继承了抽象装饰类的子类即可。
装饰器模式包括了以下几个角色:接口、具体对象、装饰类、具体装饰类。
- 接口定义了具体对象的一些实现方法;
- 具体对象定义了一些初始化操作,比如开头设计装修功能的案例中,水电装修、天花板以及粉刷墙等都是初始化操作;
- 装饰类则是一个抽象类,主要用来初始化具体对象的一个类;
- 其它的具体装饰类都继承了该抽象类。
1.接口定义:去定义具体需要实现的相关方法
- /**
- * 描述:定义一个基本装修接口
- *
- * @author yanfengzhang
- * @date 2020-04-19 13:32
- */
- public interface IDecorator {
- /**
- * 装修方法
- */
- void decorate();
- }
2.具体对象:针对需要实现的方法做初始化操作,即基本的实现
- /**
- * 描述:装修基本类
- *
- * @author yanfengzhang
- * @date 2020-04-19 13:32
- */
- public class Decorator implements IDecorator {
- /**
- * 基本实现方法
- */
- @Override
- public void decorate() {
- System.out.println("水电装修、天花板以及粉刷墙.");
- }
- }
3.装饰类:抽象类,初始化具体对象
- /**
- * 描述:基本装饰类
- *
- * @author yanfengzhang
- * @date 2020-04-19 13:34
- */
- public abstract class BaseDecorator implements IDecorator {
- private IDecorator decorator;
-
- public BaseDecorator(IDecorator decorator) {
- this.decorator = decorator;
- }
-
- /**
- * 调用装饰方法
- */
- @Override
- public void decorate() {
- if (decorator != null) {
- decorator.decorate();
- }
- }
- }
4.其他具体装饰类实现自己特性的需求
如果我们想要在基础类上添加新的装修功能,只需要基于抽象类 BaseDecorator 去实现继承类,通过构造函数调用父类,以及重写装修方法实现装修窗帘的功能即可。
- /**
- * 描述:窗帘装饰类
- *
- * @author yanfengzhang
- * @date 2020-04-19 13:35
- */
- public class CurtainDecorator extends BaseDecorator {
- public CurtainDecorator(IDecorator decorator) {
- super(decorator);
- }
-
- /**
- * 窗帘具体装饰方法
- */
- @Override
- public void decorate() {
- System.out.println("窗帘装饰。。。");
- super.decorate();
- }
- }
5.实际使用
- /**
- * 描述:具体使用测试
- *
- * @author yanfengzhang
- * @date 2020-04-19 13:36
- */
- public class Test {
- public static void main(String[] args) {
- IDecorator decorator = new Decorator();
- IDecorator curtainDecorator = new CurtainDecorator(decorator);
- curtainDecorator.decorate();
- }
- }
三、具体案例分析
每逢双十一,为了加大商城的优惠力度,开发往往要设计红包 + 限时折扣或红包 + 抵扣券等组合来实现多重优惠。而在平时,由于某些特殊原因,商家还会赠送特殊抵扣券给购买用户,而特殊抵扣券 + 各种优惠又是另一种组合方式。
要实现以上这类组合优惠的功能,刚刚介绍的装饰器模式就很适合用在这里,其相互独立、自由组合以及方便动态扩展功能的特性,可以很好地解决这类需求。
目标:用装饰器模式动手实现一套商品价格策略的优化方案。
1.先建立订单和商品的属性类:主订单+详细订单+商品+促销类型+优惠券+红包
订单和商品的属性类只建立了几个关键字段,主订单包含若干详细订单,详细订单中记录了商品信息,商品信息中包含了促销类型信息,一个商品可以包含多个促销类型(只讨论单个促销和组合促销)
- 主订单
- import java.math.BigDecimal;
- import java.util.List;
-
- /**
- * 描述:主订单
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:01
- */
- @Data
- public class Order {
- /**
- * 订单ID
- */
- private int id;
- /**
- * 订单号
- */
- private String orderNo;
- /**
- * 总支付金额
- */
- private BigDecimal totalPayMoney;
- /**
- * 详细订单列表
- */
- private List
list; - }
- 详细订单
- import java.math.BigDecimal;
-
- /**
- * 描述:详细订单
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:06
- */
- @Data
- public class OrderDetail {
- /**
- * 详细订单ID
- */
- private int id;
- /**
- * 主订单ID
- */
- private int orderId;
- /**
- * 商品详情
- */
- private Merchandise merchandise;
- /**
- * 支付单价
- */
- private BigDecimal payMoney;
- }
- 具体商品
- import java.math.BigDecimal;
- import java.util.Map;
-
- /**
- * 描述:具体商品
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:09
- */
- @Data
- public class Merchandise {
- /**
- * 商品SKU
- */
- private String sku;
- /**
- * 商品名称
- */
- private String name;
- /**
- * 商品单价
- */
- private BigDecimal price;
- /**
- * 支持促销类型
- */
- private Map
supportPromotions; - }
- 促销类型
- /**
- * 描述:促销类型
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:16
- */
- public enum PromotionType {
- /**
- * 优惠卷
- */
- COUPON,
- /**
- * 红包
- */
- REDPACKED;
- }
- 优惠券
- import java.math.BigDecimal;
-
- /**
- * 描述:优惠券
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:13
- */
- @Data
- public class UserCoupon {
- /**
- * 优惠券ID
- */
- private int id;
- /**
- * 领取优惠券用户ID
- */
- private int userId;
- /**
- * 商品SKU
- */
- private String sku;
- /**
- * 优惠金额
- */
- private BigDecimal coupon;
- }
- 红包
- import java.math.BigDecimal;
-
- /**
- * 描述:红包
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:14
- */
- @Data
- public class UserRedPacket {
- /**
- * 红包ID
- */
- private int id;
- /**
- * 领取用户ID
- */
- private int userId;
- /**
- * 商品SKU
- */
- private String sku;
- /**
- * 领取红包金额
- */
- private BigDecimal redPacket;
- }
- 促销类型
- /**
- * 描述:促销类型
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:16
- */
- @Data
- public class SupportPromotions implements Cloneable {
- /**
- * 该商品促销的ID
- */
- private int id;
- /**
- * 促销类型 1\优惠券 2\红包
- */
- private PromotionType promotionType;
- /**
- * 优先级
- */
- private int priority;
- /**
- * 用户领取该商品的优惠券
- */
- private UserCoupon userCoupon;
- /**
- * 用户领取该商品的红包
- */
- private UserRedPacket userRedPacket;
-
- /**
- * 重写clone方法
- */
- @Override
- public SupportPromotions clone() {
- SupportPromotions supportPromotions = null;
- try {
- supportPromotions = (SupportPromotions) super.clone();
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return supportPromotions;
- }
- }
2.建立计算支付金额的接口类以及基本类
- 基本接口定义
- /**
- * 描述:计算支付金额接口类
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:09
- */
-
- public interface IBaseCount {
- /**
- * 功能描述:计算支付金额
- * @author yanfengzhang
- * @date 2020-04-19 14:40
- * @param orderDetail
- * @return BigDecimal
- */
- BigDecimal countPayMoney(OrderDetail orderDetail);
- }
- 基本实现类
- /**
- * 描述:支付基本类
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:41
- */
- public class BaseCount implements IBaseCount {
- @Override
- public BigDecimal countPayMoney(OrderDetail orderDetail) {
- orderDetail.setPayMoney(orderDetail.getMerchandise().getPrice());
- System.out.println("商品原单价金额为:" + orderDetail.getPayMoney());
- return orderDetail.getPayMoney();
- }
- }
3.建立计算支付金额的抽象类(调用基本类)
- /**
- * 描述:计算支付金额的抽象类
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:48
- */
- public abstract class BaseCountDecorator implements IBaseCount {
- private IBaseCount count;
-
- public BaseCountDecorator(IBaseCount count) {
- this.count = count;
- }
-
- @Override
- public BigDecimal countPayMoney(OrderDetail orderDetail) {
- BigDecimal payTotalMoney = new BigDecimal(0);
- if (count != null) {
- payTotalMoney = count.countPayMoney(orderDetail);
- }
- return payTotalMoney;
- }
- }
4.优惠券计算类通过继承抽象类来实现所需要的修饰类
- /**
- * 描述:计算使用优惠券后的金额
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:50
- */
- public class CouponDecorator extends BaseCountDecorator {
- public CouponDecorator(IBaseCount count) {
- super(count);
- }
-
- @Override
- public BigDecimal countPayMoney(OrderDetail orderDetail) {
- BigDecimal payTotalMoney = new BigDecimal(0);
- payTotalMoney = super.countPayMoney(orderDetail);
- payTotalMoney = countCouponPayMoney(orderDetail);
- return payTotalMoney;
- }
-
- private BigDecimal countCouponPayMoney(OrderDetail orderDetail) {
- BigDecimal coupon = orderDetail.getMerchandise().getSupportPromotions().get(PromotionType.COUPON).getUserCoupon().getCoupon();
- System.out.println("优惠券金额:" + coupon);
- orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(coupon));
- return orderDetail.getPayMoney();
- }
- }
5.红包计算类通过继承抽象类来实现所需要的修饰类
- /**
- * 描述:计算使用红包后的金额
- *
- * @author yanfengzhang
- * @date 2020-04-19 15:24
- */
- public class RedPacketDecorator extends BaseCountDecorator {
-
- public RedPacketDecorator(IBaseCount count) {
- super(count);
- }
-
- @Override
- public BigDecimal countPayMoney(OrderDetail orderDetail) {
- BigDecimal payTotalMoney = new BigDecimal(0);
- payTotalMoney = super.countPayMoney(orderDetail);
- payTotalMoney = countCouponPayMoney(orderDetail);
- return payTotalMoney;
- }
-
- private BigDecimal countCouponPayMoney(OrderDetail orderDetail) {
-
- BigDecimal redPacket = orderDetail.getMerchandise().getSupportPromotions().get(PromotionType.REDPACKED).getUserRedPacket().getRedPacket();
- System.out.println("红包优惠金额:" + redPacket);
-
- orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(redPacket));
- return orderDetail.getPayMoney();
- }
- }
6.通过一个工厂类来组合商品的促销类型
- /**
- * 描述:计算促销后的支付价格
- *
- * @author yanfengzhang
- * @date 2020-04-19 14:58
- */
- public class PromotionFactory {
- public static BigDecimal getPayMoney(OrderDetail orderDetail) {
- /**获取给商品设定的促销类型*/
- Map
supportPromotionsList = orderDetail.getMerchandise().getSupportPromotions(); -
- /**初始化计算类*/
- IBaseCount baseCount = new BaseCount();
- if (supportPromotionsList != null && supportPromotionsList.size() > 0) {
- for (PromotionType promotionType : supportPromotionsList.keySet()) {
- /**遍历设置的促销类型,通过装饰器组合促销类型*/
- baseCount = protmotion(supportPromotionsList.get(promotionType), baseCount);
- }
- }
- return baseCount.countPayMoney(orderDetail);
- }
-
- /**
- * 组合促销类型 * @param supportPromotions * @param baseCount * @return
- */
- private static IBaseCount protmotion(SupportPromotions supportPromotions, IBaseCount baseCount) {
- if (supportPromotions.getPromotionType() == PromotionType.COUPON) {
- baseCount = new CouponDecorator(baseCount);
- } else if (supportPromotions.getPromotionType() == PromotionType.REDPACKED) {
- baseCount = new RedPacketDecorator(baseCount);
- }
- return baseCount;
- }
- }
7.实际使用操作
- /**
- * 描述:测试
- *
- * @author yanfengzhang
- * @date 2020-04-19 15:35
- */
- public class Test {
- volatile int counter = 0;
-
- private static Order init(Order order) {
- Map
supportPromotionslist = new HashMap(); -
- SupportPromotions supportPromotions = new SupportPromotions();
- supportPromotions.setPromotionType(PromotionType.COUPON);
- supportPromotions.setPriority(1);
-
- UserCoupon userCoupon = new UserCoupon();
- userCoupon.setCoupon(new BigDecimal(3));
- userCoupon.setSku("aaa1111");
- userCoupon.setUserId(11);
-
- supportPromotions.setUserCoupon(userCoupon);
-
- supportPromotionslist.put(PromotionType.COUPON, supportPromotions);
- SupportPromotions supportPromotions1 = supportPromotions.clone();
-
- supportPromotions1.setPromotionType(PromotionType.REDPACKED);
- supportPromotions1.setPriority(2);
-
- UserRedPacket userRedPacket = new UserRedPacket();
- userRedPacket.setId(1);
- userRedPacket.setRedPacket(new BigDecimal(10));
- userRedPacket.setSku("aaa1111");
- userCoupon.setUserId(11);
-
- supportPromotions1.setUserRedPacket(userRedPacket);
- supportPromotionslist.put(PromotionType.REDPACKED, supportPromotions1);
-
- Merchandise merchandise = new Merchandise();
- merchandise.setSku("aaa1111");
- merchandise.setName("苹果");
- merchandise.setPrice(new BigDecimal(20));
- merchandise.setSupportPromotions(supportPromotionslist);
-
- List
OrderDetailList = new ArrayList(); - OrderDetail orderDetail = new OrderDetail();
- orderDetail.setId(1);
- orderDetail.setOrderId(1111);
- orderDetail.setMerchandise(merchandise);
-
- OrderDetailList.add(orderDetail);
- order.setList(OrderDetailList);
-
- return order;
- }
-
- public static void main(String[] args) throws InterruptedException, IOException {
- Order order = new Order();
- init(order);
-
- for (OrderDetail orderDetail : order.getList()) {
- BigDecimal payMoney = PromotionFactory.getPayMoney(orderDetail);
- orderDetail.setPayMoney(payMoney);
- System.out.println("最终支付金额:" + orderDetail.getPayMoney());
- }
- }
- }
实际测试输入:
- 商品原单价金额为:20
- 红包优惠金额:10
- 优惠券金额:3
- 最终支付金额:7
参考书籍、文献和资料
1.极客时间课程《Java性能调优实战》,刘超,2019.
评论记录:
回复评论: