1. 策略模式介绍

策略模式是一种行为模式,也是替代大量ifelse的利器。它所能解决的场景,一般是具有同类可替代的行为逻辑算法场景。比如,不同类型的交易方式(信用卡、支付宝、微信)、生成唯一ID策略(UUID、DB自增、DB+Redis、雪花算法、Leaf算法)等,都可以使用策略模式进行包装,供给外部使用。

策略模式有点像三国演义中诸葛亮给刘关张的锦囊:

  • 第一个锦囊:见乔国老,并把刘备娶亲的事情搞得东吴人尽皆知。
  • 第二个锦囊:用曹操打荆州的谎言骗跑在温柔乡的刘备回去。
  • 第三个锦囊:让孙夫人摆平东吴的追兵,她是孙权妹妹,东吴将领惧她三分。

2. 案例场景模拟

在本案例中我们模拟在购物时使用的各种类型的优惠券(满减、直减、折扣、n元购)。

这个场景几乎也是大家的一个日常购物省钱渠道,我们希望找一些优惠券,让购买的商品更加实惠,而且到了大促会有更多的优惠券需要计算哪些商品一起购买更加优惠。

这样的场景用户用起来还是蛮爽的,但是随着产品的不断迭代,对于程序员开发还是不容易的。因为这里包括了很多的规则和优惠逻辑,所以我们模拟其中的一个计算优惠的方式,使用策略模式来实现。

3. 用一坨坨代码实现

对于优惠券的设计最初可能非常简单,就是一个金额的折扣,也没有现在这么多种类型。所以如果没有这样场景的经验的话,往往设计上也是非常简单的。但随着产品功能的不断迭代,如果程序最初设计的不具有很好的扩展性,那么往后就会越来越混乱。

工程结构

org.itstack.demo.design
----CouponDiscountService.java
  • 一坨坨工程的结构很简单,也是最直接的面向过程开发方式。

代码实现

public class CouponDiscountService {public double discountAmount(int type, double typeContent, double skuPrice, double typeExt) {// 1. 直减券if (1 == type) {return skuPrice - typeContent;}// 2. 满减券if (2 == type) {if (skuPrice < typeExt) return skuPrice;return skuPrice - typeContent;}// 3. 折扣券if (3 == type) {return skuPrice * typeContent;}// 4. n元购if (4 == type) {return typeContent;}return 0D;}
}
  • 入参包括:优惠券类型type、优惠券金额typeContent、商品金额skuPrice,因为有些优惠券是满多少减多少,所以增加typeExt,这也是方法的不好扩展的问题。
  • 最后整个的方法体对优惠券抵扣金额的实现,最开始可能是一个最简单的优惠券,后面随着产品功能的增加,不断的扩展if语句,实际的代码比这个要多得多。

4. 策略模式重构代码

与上面面向流程式的开发这里会使用设计模式,优化代码结构,增强整理的扩展性。

工程结构

org.itstack.demo.design
----event----MJCouponDiscount.java----NYGCouponDiscount.java----ZJCouponDiscount.java----ZKCouponDiscount.java
----Context.java
----ICouponDiscount.java

策略模式模型结构

  • 整体的结构模式并不复杂,主要体现的不同类型的优惠券在计算优惠券方式的不同计算策略。
  • 这里包括一个接口类ICouponDiscount,以及4种优惠券类型的实现方式。
  • 最后提供了策略模式的上下控制类处理整体的策略服务。

代码实现

优惠券接口

public interface ICouponDiscount<T> {/*** 优惠券金额计算* @param couponInfo 券折扣信息:直减、满减、折扣、N元购* @param skuPrice sku金额* @return 优惠后金额*/BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice);
}
  • 定义了优惠券折扣接口,也增加了泛型用于不同类型的接口可以传递不同的类型参数。
  • 接口中包含商品金额以及出参返回最终折扣后的金额,在实际开发中会比现在的接口参数多一些,但核心逻辑是这些。

满减接口实现

public class MJCouponDiscount implements ICouponDiscount<Map<String,String>> {/*** 满减计算* 1. 判断满足x元后-n元* 2. 最低支付金额1元*/public BigDecimal discountAmount(Map<String,String> couponInfo,BigDecimal skuPrice) {String x = couponInfo.get("x");String o = couponInfo.get("n");// 小于条件金额的,直接返回原价if (skuPrice.compareTo(new BigDecimal(x)) < 0) return skuPrice;// 减去优惠金额判断BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(o));if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;return discountAmount;}
}

直减接口实现

public class ZJCouponDiscount implements ICouponDiscount<Double> {/*** 直减计算* 1. 商品价格-优惠价格* 2. 最低支付金额1元*/public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {BigDecimal discountAmount = skuPrice.subtract(new BigDecimal(couponInfo));if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;return discountAmount;}
}

折扣接口实现

public class ZKCouponDiscount implements ICouponDiscount<Double> {/*** 折扣计算* 1. 商品价格X折扣比例* 2. 保留两位小数* 3. 最低支付金额1元*/public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {BigDecimal discountAmount = skuPrice.multiply(new BigDecimal(couponInfo)).setScale(2, BigDecimal.ROUND_HALF_UP);if (discountAmount.compareTo(BigDecimal.ZERO) < 1) return BigDecimal.ONE;return discountAmount;}
}

N元购

public class NYGCouponDiscount implements ICouponDiscount<Double> {/*** n元购计算* 1. 无论原价多少都固定金额购买*/public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) {return new BigDecimal(couponInfo);}
}
  • 以上是4种不同类型的优惠券计算折扣金额的策略方式。

策略控制类

public class Context<T> {private ICouponDiscount<T> couponDiscount;public Context(ICouponDiscount<T> couponDiscount) {this.couponDiscount = couponDiscount;}public BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice) {return couponDiscount.discountAmount(couponInfo, skuPrice);}
}
  • 策略模式的控制类主要是外部可以传递不同的策略实现,在通过统一的方法执行优惠策略计算。
  • 另外这里也可以包装成map结构,让外部只需要对应的泛型类型即可使用对应的服务。

测试验证

编写测试类

@Test
public void test_zj() {// 直减:100-10Context<Double> context = new Context<Double>(new ZJCouponDiscount());BigDecimal discountAmount = context.discountAmount(10D, new BigDecimal(100));logger.info("测试结果:直减优惠后金额 {}", discountAmount);// 满减:满100-10Context<Map<String,String>> context = new Context<Map<String,String>> (new MJCouponDiscount());Map<String,String> mapReq = new HashMap<String, String>();mapReq.put("x","100");mapReq.put("n","10");BigDecimal discountAmount = context.discountAmount(mapReq, new BigDecimal(100));logger.info("测试结果:满减优惠后金额 {}", discountAmount);// 折扣9折Context<Double> context = new Context<Double>(new ZKCouponDiscount());BigDecimal discountAmount = context.discountAmount(0.9D, new BigDecimal(100));logger.info("测试结果:折扣9折后金额 {}", discountAmount);// n元购Context<Double> context = new Context<Double>(new NYGCouponDiscount());BigDecimal discountAmount = context.discountAmount(90D, new BigDecimal(100));logger.info("测试结果:n元购优惠后金额 {}", discountAmount);
}

测试结果

15:43:22.035 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:直减优惠后金额 90
15:43:42.695 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:满减优惠后金额 90
15:44:05.602 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:折扣9折后金额 90.00
15:44:24.700 [main] INFO org.itstack.demo.design.test.ApiTest - 测试结果:n元购优惠后金额 90    Process finished with exit code 0
  • 以上分别验证了不同类型的优惠券的优惠策略,测试结果满足我们的预期。

5. 总结

  • 以上的策略模式案例相对来说并不复杂,主要的逻辑都是体现在关于不同种类优惠券的计算折扣策略上。结构也相对简单,在实际的开发中这样的设计模式也是非常常见的。另外,这样的设计与命令模式、适配器模式结构相似,但思路是有差异的。
  • 通过策略模式的使用可以把我们方法中的if语句优化掉,满足设计原则中的隔离性和扩展性。
  • 策略模式、适配器模式、组合模式在一些结构上比较相似,但是每一个模式是有自己的逻辑特点的,在后续过程中需要去慢慢体会和实现。

行为模式之策略模式的案例示范相关推荐

  1. ×××站点的路由(隧道、接口)模式和策略模式

    常接触思科设备的都知道,目前使用IPsec协议建立的×××站点都是无法使用路由的,要么采用GRE技术,GRE over IPsec可以实现路由,不过那样配置复杂不说,由于2次封装,每个数据包的有效载荷 ...

  2. 责任链模式与策略模式

    责任链模式 Chain of Responsibility(CoR)模式也叫职责链模式或者职责连锁模式,是行为模式之一,该模式构造一系列分别担当不同的职责的类的对象来共同完成一个任务,这些类的对象之间 ...

  3. 策略模式、策略模式与Spring的碰撞

    策略模式是GoF23种设计模式中比较简单的了,也是常用的设计模式之一,今天我们就来看看策略模式. 实际案例 我工作第三年的时候,重构旅游路线的机票查询模块,旅游路线分为四种情况: 如果A地-B地往返都 ...

  4. 设计模式学习笔记(二)工厂模式、模板模式和策略模式的混合使用

    一.工厂模式(Factory pattern) 工厂模式又叫做工厂方法模式,是一种创建型设计模式,一般是在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型. 1.1 工厂模式介绍 工厂模式是 ...

  5. 设计模式之模板方法模式、策略模式、命令模式、责任链模式、状态模式

    前言 本章节给您介绍23种设计模式的行为型模式中的模板方法模式.策略模式.命令模式.责任链模式.状态模式. 如有帮助记得3连 加 关注哦!欢迎品论去留言交流,谢谢阅读! 文章目录 前言 一.模板方法模 ...

  6. 拿捏大厂面试,设计模式学习笔记(二)工厂模式、模板模式和策略模式的混合使用

    一.工厂模式 工厂模式又叫做工厂方法模式,是一种创建型设计模式,一般是在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型. 1.1 工厂模式介绍 工厂模式是Java 中比较常见的一种设计模式 ...

  7. 工厂模式和策略模式的综合使用

    目录 一.简单的工厂模式了解与使用 (一)基本概念理解 (二)简单工厂模式的认识和对应角色的分析 基本认识 角色理解 (三)使用场景和典型应用 二.简单的策略模式了解与使用 (一)基本概念理解 (二) ...

  8. C++模式学习------策略模式

    当遇到同一个对象有不同的行为,方法,为管理这些方法可使用策略模式. 策略模式就是对算法进行包装,是把使用算法的责任和算法本身分割开来.通常把一个系列的算法包装到一系列的策略类里面,这些类继承一个抽象的 ...

  9. 我学的是设计模式的视频教程——命令模式vs策略模式,唠嗑

    课程视频 命令模式vs策略模式 唠嗑 课程笔记 课程笔记 课程代码 课程代码 新课程火热报名中 课程介绍 版权声明:本文博主原创文章,博客,未经同意不得转载.

最新文章

  1. suse linux显示乱码,open suse11.4中文乱码问题
  2. Python openpyxl 之 Excel 文档简单操作
  3. 牛客算法周周练2 B Music Problem(DP,抽屉原理,二进制拆分)
  4. 管理单元初始化失败解决办法
  5. TCP/IP拥塞控制复习
  6. Opencv显示创建Mat对象的七种方式
  7. 心脏遥测监控系统服务器,基于ARM7的心电采集与远程传输系统设计
  8. 稳扎稳打Silverlight(18) - 2.0视频之详解MediaElement, 开发一个简易版的全功能播放器...
  9. 我的第一个博客正式注册
  10. java中sql查找_Java 中如何使用 SQL 查询文本
  11. PHP 将文字转化mp3文件
  12. 基于GD32F450+USB3300的高速USB传输
  13. 利用计算机视觉看懂病历,广东省中山市2019年九年级下册中考语文第二次模拟测试语文试题卷(二模含答案和解析).doc...
  14. [转]《牵一只蜗牛去散步》台湾 张文亮
  15. Android 微信支付总结
  16. Nazo前三十三关攻略
  17. Activiti,自定义表单,外置表单,工作流,微服务,子系统
  18. 玩转外贸LinkedIn必备的三大特质,以及突破六度人脉技巧
  19. Unknown Faceted Project Problem (Java Version Mismatch)
  20. 业务建模七大关键应用场景

热门文章

  1. “NOSQL” 杂谈
  2. wincc版本升级_关于WINCC升级问题
  3. Gtalk基本功能完成
  4. 《程序员羊皮卷》荣升当当IT图书飙升榜第一名
  5. 埃航CEO:到现场时浓烟滚滚 失事飞机机长曾想返航
  6. 从 Option Explicit 开始的零碎知识点
  7. AI真的快让我失业了
  8. 常见的数据库优化方法
  9. 数据库的查询优化方法
  10. 不坑盒子 + 智能写作(Office、WPS插件)助你高效办公,早点下班回家。