策略模式介绍
介绍
策略模式(Strategy Pattern),属于行为型模式(Behavioral Patterns),指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
eg:每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。
eg:旅行的出游方式有很多,根据去的地点,可以选择骑自行车、坐汽车或者飞机,各种出游方式都是一个策略。
优缺点
优点: 可以优化⽅法中的ifelse语句,⼤量的ifelse语句使⽤会让代码难以扩展,也不好维护,同时在后期遇到各种问题也很难维护。在使⽤策略模式后可以很好的满⾜隔离性与和扩展性,对于不断新增的需求也⾮常⽅便承接。
缺点:(1)策略类会增多。(2)所有策略类都需要对外暴露。
解决的场景
⼀般是具有同类可替代的⾏为逻辑算法场景。⽐如;不同类型的交易⽅式(信⽤卡、⽀付宝、微信)、⽣成唯⼀ID策略(UUID、DB⾃增、DB+Redis、雪花算法、Leaf算法)等,都可以使⽤策略模式进⾏⾏为包装,供给外部使⽤。
实现
(1)定义活动的 Strategy 接口
(2)实现了 Strategy 接口的实体策略类。
(3)Context 是一个使用了某种策略的类。
示例分析
优惠券折扣计算(优惠券类型; 1. 无门槛卷,2. 满减券,3. 折扣券)
没用策略模式
/** * 优惠券折扣计算接口(没用设计模式) * 优惠券类型; 1. 无门槛卷,2. 满减券,3. 折扣券 * * @author 佛大Java程序员 */ public class CouponDiscountService { /** * @param type 优惠劵类型 * @param couponPrice 优惠劵金额 * @param discount 折扣 * @param skuPrice 商品价格 * @param limitPrice 满足满减条件的金额 * @return */ public double discountAmount(int type, double couponPrice, double discount, double skuPrice, double limitPrice) { // 1. 无门槛卷 if (1 == type) { return skuPrice - couponPrice; } // 2. 满减券 if (2 == type) { if (skuPrice < limitPrice) { return skuPrice; } //如果商品价格达到满减金额limitPrice return skuPrice - couponPrice; } // 3. 折扣券 if (3 == type) { //商品价格乘以折扣 return skuPrice * discount; } return 0D; } }
使用策略模式
策略类
/** * 定义活动的策略类(Strategy)接口 * <p> * 优惠券折扣计算接口 * 优惠券类型; * 1. 直减券 * 2. 满减券 * 3. 折扣券 * * @author 佛大Java程序员 */ public interface ICouponDiscountStrategy<T> { /** * 优惠券金额计算 * * @param couponInfo 券折扣信息;直减、满减、折扣 * @param skuPrice sku金额
* * @return 优惠后金额 */ BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice); }
实现了 Strategy 接口的实体策略类
满减卷实现类
/** * 实现了 Strategy 接口的实体策略类 * 满减卷 * * @author 佛大Java程序员 */ public class MJCouponDiscount implements ICouponDiscountStrategy<Map<String, String>> { /** * 满减计算 * 1. 判断满足x元后-n元,否则不减 * 2. 最低支付金额1元 */ @Override 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; } }
无门槛优惠劵实现类
/** * 实现了 Strategy 接口的实体策略类 * 无门槛优惠劵 * * @author 佛大Java程序员 */ public class ZJCouponDiscount implements ICouponDiscountStrategy<Double> { /** * 直减计算 * 1. 使用商品价格减去优惠价格 * 2. 最低支付金额1元 */ @Override 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; } }
折扣卷实现类
/** * 实现了 Strategy 接口的实体策略类 * 折扣卷实现类 * * @author 佛大Java程序员 */ public class ZKCouponDiscount implements ICouponDiscountStrategy<Double> { /** * 折扣计算 * 1. 使用商品价格乘以折扣比例,为最后支付金额 * 2. 保留两位小数 * 3. 最低支付金额1元 */ @Override 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; } }
Context 是一个使用了某种策略的类
/** * Context 是一个使用了某种策略的类 * * @author 佛大Java程序员 */ public class CouponDiscountContext<T> { private ICouponDiscountStrategy<T> iCouponDiscountStrategy; public CouponDiscountContext(ICouponDiscountStrategy<T> couponDiscount) { this.iCouponDiscountStrategy = couponDiscount; } public BigDecimal discountAmount(T couponInfo, BigDecimal skuPrice) { return iCouponDiscountStrategy.discountAmount(couponInfo, skuPrice); } }
测试类
/** * 测试类 * * @author 佛大java程序员 */ public class ApiTest { private Logger logger = LoggerFactory.getLogger(ApiTest.class); @org.junit.Test public void test_zj() { // 直减;100-10,商品100元 CouponDiscountContext<Double> context = new CouponDiscountContext<>(new ZJCouponDiscount()); BigDecimal discountAmount = context.discountAmount(10D, new BigDecimal(100)); logger.info("测试结果:直减优惠后金额 {}", discountAmount); } @Test public void test_mj() { // 满100减10,商品100元 CouponDiscountContext<Map<String, String>> context = new CouponDiscountContext<>(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); } @Test public void test_zk() { // 折扣9折,商品100元 CouponDiscountContext<Double> context = new CouponDiscountContext<>(new ZKCouponDiscount()); BigDecimal discountAmount = context.discountAmount(0.9D, new BigDecimal(100)); logger.info("测试结果:折扣9折后金额 {}", discountAmount); } }
运行结果
希望本文章对您有帮助,您的转发、点赞是我的创作动力,十分感谢。更多好文推荐,请关注我的微信公众号--JustJavaIt