首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

掌握装饰器模式:概念、用法及商品价格策略优化案例

  • 25-03-02 12:01
  • 2371
  • 10391
blog.csdn.net

目录

一、装饰器模式的概念及怎么用?

1.基本概念和功能

2.结构图分析

3.举例分析

二、装饰器模式的基本用法

1.接口定义:去定义具体需要实现的相关方法

2.具体对象:针对需要实现的方法做初始化操作,即基本的实现

3.装饰类:抽象类,初始化具体对象

4.其他具体装饰类实现自己特性的需求

5.实际使用

三、具体案例分析

目标:用装饰器模式动手实现一套商品价格策略的优化方案。

1.先建立订单和商品的属性类:主订单+详细订单+商品+促销类型+优惠券+红包

2.建立计算支付金额的接口类以及基本类

3.建立计算支付金额的抽象类(调用基本类)

4.优惠券计算类通过继承抽象类来实现所需要的修饰类

5.红包计算类通过继承抽象类来实现所需要的修饰类

6.通过一个工厂类来组合商品的促销类型

7.实际使用操作

参考书籍、文献和资料


干货分享,感谢您的阅读!

一、装饰器模式的概念及怎么用?

1.基本概念和功能

装饰器模式能够实现从一个对象的外部来给对象添加功能,有非常灵活的扩展性,可以在对原来的代码毫无修改的前提下,为对象添加新功能。除此之外,装饰器模式还能够实现对象的动态组合,借此我们可以很灵活地给动态组合的对象,匹配所需要的功能。

2.结构图分析

  • Component为统一接口,也是装饰类和被装饰类的基本类型。
  • ConcreteComponent为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类。
  • Decorator是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。而Decorator本身,通常采用默认实现,他的存在仅仅是一个声明:我要生产出一些用于装饰的子类了。而其子类才是赋有具体装饰效果的装饰产品类。
  • ConcreteDecorator是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent,从而对其进行装饰。

3.举例分析

假设现在有这样一个需求,让你设计一个装修功能,用户可以动态选择不同的装修功能来装饰自己的房子。例如,水电装修、天花板以及粉刷墙等属于基本功能,而设计窗帘装饰窗户、设计吊顶装饰房顶等未必是所有用户都需要的,这些功能则需要实现动态添加。还有就是一旦有新的装修功能,我们也可以实现动态添加。

采用装饰器模式可以很好的解决以上问题。

二、装饰器模式的基本用法

基于装饰器模式实现的装修功能的代码结构简洁易读,业务逻辑也非常清晰,并且如果我们需要扩展新的装修功能,只需要新增一个继承了抽象装饰类的子类即可。

装饰器模式包括了以下几个角色:接口、具体对象、装饰类、具体装饰类。

  • 接口定义了具体对象的一些实现方法;
  • 具体对象定义了一些初始化操作,比如开头设计装修功能的案例中,水电装修、天花板以及粉刷墙等都是初始化操作;
  • 装饰类则是一个抽象类,主要用来初始化具体对象的一个类;
  • 其它的具体装饰类都继承了该抽象类。

1.接口定义:去定义具体需要实现的相关方法

  1. /**
  2. * 描述:定义一个基本装修接口
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 13:32
  6. */
  7. public interface IDecorator {
  8. /**
  9. * 装修方法
  10. */
  11. void decorate();
  12. }

2.具体对象:针对需要实现的方法做初始化操作,即基本的实现

  1. /**
  2. * 描述:装修基本类
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 13:32
  6. */
  7. public class Decorator implements IDecorator {
  8. /**
  9. * 基本实现方法
  10. */
  11. @Override
  12. public void decorate() {
  13. System.out.println("水电装修、天花板以及粉刷墙.");
  14. }
  15. }

3.装饰类:抽象类,初始化具体对象

  1. /**
  2. * 描述:基本装饰类
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 13:34
  6. */
  7. public abstract class BaseDecorator implements IDecorator {
  8. private IDecorator decorator;
  9. public BaseDecorator(IDecorator decorator) {
  10. this.decorator = decorator;
  11. }
  12. /**
  13. * 调用装饰方法
  14. */
  15. @Override
  16. public void decorate() {
  17. if (decorator != null) {
  18. decorator.decorate();
  19. }
  20. }
  21. }

4.其他具体装饰类实现自己特性的需求

如果我们想要在基础类上添加新的装修功能,只需要基于抽象类 BaseDecorator 去实现继承类,通过构造函数调用父类,以及重写装修方法实现装修窗帘的功能即可。

  1. /**
  2. * 描述:窗帘装饰类
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 13:35
  6. */
  7. public class CurtainDecorator extends BaseDecorator {
  8. public CurtainDecorator(IDecorator decorator) {
  9. super(decorator);
  10. }
  11. /**
  12. * 窗帘具体装饰方法
  13. */
  14. @Override
  15. public void decorate() {
  16. System.out.println("窗帘装饰。。。");
  17. super.decorate();
  18. }
  19. }

5.实际使用

  1. /**
  2. * 描述:具体使用测试
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 13:36
  6. */
  7. public class Test {
  8. public static void main(String[] args) {
  9. IDecorator decorator = new Decorator();
  10. IDecorator curtainDecorator = new CurtainDecorator(decorator);
  11. curtainDecorator.decorate();
  12. }
  13. }

三、具体案例分析

每逢双十一,为了加大商城的优惠力度,开发往往要设计红包 + 限时折扣或红包 + 抵扣券等组合来实现多重优惠。而在平时,由于某些特殊原因,商家还会赠送特殊抵扣券给购买用户,而特殊抵扣券 + 各种优惠又是另一种组合方式。

要实现以上这类组合优惠的功能,刚刚介绍的装饰器模式就很适合用在这里,其相互独立、自由组合以及方便动态扩展功能的特性,可以很好地解决这类需求。

目标:用装饰器模式动手实现一套商品价格策略的优化方案。

1.先建立订单和商品的属性类:主订单+详细订单+商品+促销类型+优惠券+红包

订单和商品的属性类只建立了几个关键字段,主订单包含若干详细订单,详细订单中记录了商品信息,商品信息中包含了促销类型信息,一个商品可以包含多个促销类型(只讨论单个促销和组合促销)

  • 主订单
  1. import java.math.BigDecimal;
  2. import java.util.List;
  3. /**
  4. * 描述:主订单
  5. *
  6. * @author yanfengzhang
  7. * @date 2020-04-19 14:01
  8. */
  9. @Data
  10. public class Order {
  11. /**
  12. * 订单ID
  13. */
  14. private int id;
  15. /**
  16. * 订单号
  17. */
  18. private String orderNo;
  19. /**
  20. * 总支付金额
  21. */
  22. private BigDecimal totalPayMoney;
  23. /**
  24. * 详细订单列表
  25. */
  26. private List list;
  27. }
  • 详细订单
  1. import java.math.BigDecimal;
  2. /**
  3. * 描述:详细订单
  4. *
  5. * @author yanfengzhang
  6. * @date 2020-04-19 14:06
  7. */
  8. @Data
  9. public class OrderDetail {
  10. /**
  11. * 详细订单ID
  12. */
  13. private int id;
  14. /**
  15. * 主订单ID
  16. */
  17. private int orderId;
  18. /**
  19. * 商品详情
  20. */
  21. private Merchandise merchandise;
  22. /**
  23. * 支付单价
  24. */
  25. private BigDecimal payMoney;
  26. }
  • 具体商品
  1. import java.math.BigDecimal;
  2. import java.util.Map;
  3. /**
  4. * 描述:具体商品
  5. *
  6. * @author yanfengzhang
  7. * @date 2020-04-19 14:09
  8. */
  9. @Data
  10. public class Merchandise {
  11. /**
  12. * 商品SKU
  13. */
  14. private String sku;
  15. /**
  16. * 商品名称
  17. */
  18. private String name;
  19. /**
  20. * 商品单价
  21. */
  22. private BigDecimal price;
  23. /**
  24. * 支持促销类型
  25. */
  26. private Map supportPromotions;
  27. }
  • 促销类型
  1. /**
  2. * 描述:促销类型
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 14:16
  6. */
  7. public enum PromotionType {
  8. /**
  9. * 优惠卷
  10. */
  11. COUPON,
  12. /**
  13. * 红包
  14. */
  15. REDPACKED;
  16. }
  • 优惠券
  1. import java.math.BigDecimal;
  2. /**
  3. * 描述:优惠券
  4. *
  5. * @author yanfengzhang
  6. * @date 2020-04-19 14:13
  7. */
  8. @Data
  9. public class UserCoupon {
  10. /**
  11. * 优惠券ID
  12. */
  13. private int id;
  14. /**
  15. * 领取优惠券用户ID
  16. */
  17. private int userId;
  18. /**
  19. * 商品SKU
  20. */
  21. private String sku;
  22. /**
  23. * 优惠金额
  24. */
  25. private BigDecimal coupon;
  26. }
  • 红包
  1. import java.math.BigDecimal;
  2. /**
  3. * 描述:红包
  4. *
  5. * @author yanfengzhang
  6. * @date 2020-04-19 14:14
  7. */
  8. @Data
  9. public class UserRedPacket {
  10. /**
  11. * 红包ID
  12. */
  13. private int id;
  14. /**
  15. * 领取用户ID
  16. */
  17. private int userId;
  18. /**
  19. * 商品SKU
  20. */
  21. private String sku;
  22. /**
  23. * 领取红包金额
  24. */
  25. private BigDecimal redPacket;
  26. }
  • 促销类型
  1. /**
  2. * 描述:促销类型
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 14:16
  6. */
  7. @Data
  8. public class SupportPromotions implements Cloneable {
  9. /**
  10. * 该商品促销的ID
  11. */
  12. private int id;
  13. /**
  14. * 促销类型 1\优惠券 2\红包
  15. */
  16. private PromotionType promotionType;
  17. /**
  18. * 优先级
  19. */
  20. private int priority;
  21. /**
  22. * 用户领取该商品的优惠券
  23. */
  24. private UserCoupon userCoupon;
  25. /**
  26. * 用户领取该商品的红包
  27. */
  28. private UserRedPacket userRedPacket;
  29. /**
  30. * 重写clone方法
  31. */
  32. @Override
  33. public SupportPromotions clone() {
  34. SupportPromotions supportPromotions = null;
  35. try {
  36. supportPromotions = (SupportPromotions) super.clone();
  37. } catch (CloneNotSupportedException e) {
  38. e.printStackTrace();
  39. }
  40. return supportPromotions;
  41. }
  42. }

2.建立计算支付金额的接口类以及基本类

  • 基本接口定义
  1. /**
  2. * 描述:计算支付金额接口类
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 14:09
  6. */
  7. public interface IBaseCount {
  8. /**
  9. * 功能描述:计算支付金额
  10. * @author yanfengzhang
  11. * @date 2020-04-19 14:40
  12. * @param orderDetail
  13. * @return BigDecimal
  14. */
  15. BigDecimal countPayMoney(OrderDetail orderDetail);
  16. }
  • 基本实现类
  1. /**
  2. * 描述:支付基本类
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 14:41
  6. */
  7. public class BaseCount implements IBaseCount {
  8. @Override
  9. public BigDecimal countPayMoney(OrderDetail orderDetail) {
  10. orderDetail.setPayMoney(orderDetail.getMerchandise().getPrice());
  11. System.out.println("商品原单价金额为:" + orderDetail.getPayMoney());
  12. return orderDetail.getPayMoney();
  13. }
  14. }

3.建立计算支付金额的抽象类(调用基本类)

  1. /**
  2. * 描述:计算支付金额的抽象类
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 14:48
  6. */
  7. public abstract class BaseCountDecorator implements IBaseCount {
  8. private IBaseCount count;
  9. public BaseCountDecorator(IBaseCount count) {
  10. this.count = count;
  11. }
  12. @Override
  13. public BigDecimal countPayMoney(OrderDetail orderDetail) {
  14. BigDecimal payTotalMoney = new BigDecimal(0);
  15. if (count != null) {
  16. payTotalMoney = count.countPayMoney(orderDetail);
  17. }
  18. return payTotalMoney;
  19. }
  20. }

4.优惠券计算类通过继承抽象类来实现所需要的修饰类

  1. /**
  2. * 描述:计算使用优惠券后的金额
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 14:50
  6. */
  7. public class CouponDecorator extends BaseCountDecorator {
  8. public CouponDecorator(IBaseCount count) {
  9. super(count);
  10. }
  11. @Override
  12. public BigDecimal countPayMoney(OrderDetail orderDetail) {
  13. BigDecimal payTotalMoney = new BigDecimal(0);
  14. payTotalMoney = super.countPayMoney(orderDetail);
  15. payTotalMoney = countCouponPayMoney(orderDetail);
  16. return payTotalMoney;
  17. }
  18. private BigDecimal countCouponPayMoney(OrderDetail orderDetail) {
  19. BigDecimal coupon = orderDetail.getMerchandise().getSupportPromotions().get(PromotionType.COUPON).getUserCoupon().getCoupon();
  20. System.out.println("优惠券金额:" + coupon);
  21. orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(coupon));
  22. return orderDetail.getPayMoney();
  23. }
  24. }

5.红包计算类通过继承抽象类来实现所需要的修饰类

  1. /**
  2. * 描述:计算使用红包后的金额
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 15:24
  6. */
  7. public class RedPacketDecorator extends BaseCountDecorator {
  8. public RedPacketDecorator(IBaseCount count) {
  9. super(count);
  10. }
  11. @Override
  12. public BigDecimal countPayMoney(OrderDetail orderDetail) {
  13. BigDecimal payTotalMoney = new BigDecimal(0);
  14. payTotalMoney = super.countPayMoney(orderDetail);
  15. payTotalMoney = countCouponPayMoney(orderDetail);
  16. return payTotalMoney;
  17. }
  18. private BigDecimal countCouponPayMoney(OrderDetail orderDetail) {
  19. BigDecimal redPacket = orderDetail.getMerchandise().getSupportPromotions().get(PromotionType.REDPACKED).getUserRedPacket().getRedPacket();
  20. System.out.println("红包优惠金额:" + redPacket);
  21. orderDetail.setPayMoney(orderDetail.getPayMoney().subtract(redPacket));
  22. return orderDetail.getPayMoney();
  23. }
  24. }

6.通过一个工厂类来组合商品的促销类型

  1. /**
  2. * 描述:计算促销后的支付价格
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 14:58
  6. */
  7. public class PromotionFactory {
  8. public static BigDecimal getPayMoney(OrderDetail orderDetail) {
  9. /**获取给商品设定的促销类型*/
  10. Map supportPromotionsList = orderDetail.getMerchandise().getSupportPromotions();
  11. /**初始化计算类*/
  12. IBaseCount baseCount = new BaseCount();
  13. if (supportPromotionsList != null && supportPromotionsList.size() > 0) {
  14. for (PromotionType promotionType : supportPromotionsList.keySet()) {
  15. /**遍历设置的促销类型,通过装饰器组合促销类型*/
  16. baseCount = protmotion(supportPromotionsList.get(promotionType), baseCount);
  17. }
  18. }
  19. return baseCount.countPayMoney(orderDetail);
  20. }
  21. /**
  22. * 组合促销类型 * @param supportPromotions * @param baseCount * @return
  23. */
  24. private static IBaseCount protmotion(SupportPromotions supportPromotions, IBaseCount baseCount) {
  25. if (supportPromotions.getPromotionType() == PromotionType.COUPON) {
  26. baseCount = new CouponDecorator(baseCount);
  27. } else if (supportPromotions.getPromotionType() == PromotionType.REDPACKED) {
  28. baseCount = new RedPacketDecorator(baseCount);
  29. }
  30. return baseCount;
  31. }
  32. }

7.实际使用操作

  1. /**
  2. * 描述:测试
  3. *
  4. * @author yanfengzhang
  5. * @date 2020-04-19 15:35
  6. */
  7. public class Test {
  8. volatile int counter = 0;
  9. private static Order init(Order order) {
  10. Map supportPromotionslist = new HashMap();
  11. SupportPromotions supportPromotions = new SupportPromotions();
  12. supportPromotions.setPromotionType(PromotionType.COUPON);
  13. supportPromotions.setPriority(1);
  14. UserCoupon userCoupon = new UserCoupon();
  15. userCoupon.setCoupon(new BigDecimal(3));
  16. userCoupon.setSku("aaa1111");
  17. userCoupon.setUserId(11);
  18. supportPromotions.setUserCoupon(userCoupon);
  19. supportPromotionslist.put(PromotionType.COUPON, supportPromotions);
  20. SupportPromotions supportPromotions1 = supportPromotions.clone();
  21. supportPromotions1.setPromotionType(PromotionType.REDPACKED);
  22. supportPromotions1.setPriority(2);
  23. UserRedPacket userRedPacket = new UserRedPacket();
  24. userRedPacket.setId(1);
  25. userRedPacket.setRedPacket(new BigDecimal(10));
  26. userRedPacket.setSku("aaa1111");
  27. userCoupon.setUserId(11);
  28. supportPromotions1.setUserRedPacket(userRedPacket);
  29. supportPromotionslist.put(PromotionType.REDPACKED, supportPromotions1);
  30. Merchandise merchandise = new Merchandise();
  31. merchandise.setSku("aaa1111");
  32. merchandise.setName("苹果");
  33. merchandise.setPrice(new BigDecimal(20));
  34. merchandise.setSupportPromotions(supportPromotionslist);
  35. List OrderDetailList = new ArrayList();
  36. OrderDetail orderDetail = new OrderDetail();
  37. orderDetail.setId(1);
  38. orderDetail.setOrderId(1111);
  39. orderDetail.setMerchandise(merchandise);
  40. OrderDetailList.add(orderDetail);
  41. order.setList(OrderDetailList);
  42. return order;
  43. }
  44. public static void main(String[] args) throws InterruptedException, IOException {
  45. Order order = new Order();
  46. init(order);
  47. for (OrderDetail orderDetail : order.getList()) {
  48. BigDecimal payMoney = PromotionFactory.getPayMoney(orderDetail);
  49. orderDetail.setPayMoney(payMoney);
  50. System.out.println("最终支付金额:" + orderDetail.getPayMoney());
  51. }
  52. }
  53. }

实际测试输入:

  1. 商品原单价金额为:20
  2. 红包优惠金额:10
  3. 优惠券金额:3
  4. 最终支付金额:7

参考书籍、文献和资料

1.极客时间课程《Java性能调优实战》,刘超,2019.

2.https://www.cnblogs.com/jzb-blog/p/6717349.html

注:本文转载自blog.csdn.net的张彦峰ZYF的文章"https://zyfcodes.blog.csdn.net/article/details/105608235"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top