策略模式介绍
策略模式是一种行为模式,也是替代if…else的利器。他能解决的场景一般包括具有同类可替代的行为逻辑算法,比如不同的交易方式等。
简单使用场景
模拟购物商品时使用的各类优惠券,包括满减、直减、折扣和N元购等。
这个场景大家都不会陌生,在购买商品时使用优惠券。在大促时,会有更多的优惠券,需要计算哪些商品一起购买更加优惠。实现此功能并不容易,因为里面包括了很多的规则和优惠逻辑,可以模拟其中一种计算优惠的方式,使用策略模式实现。
当然对于优惠的设计,最初可能非常简单,只是一个金额的抵扣,可没有很多的类型,所以虽然设计起来非常简单,但随着产品功能的不断迭代,一旦程序不具备很好的扩展性,就会越来越混乱。
策略模式实现商品优惠使用场景
整体结构并不复杂,主要体现不同类型的优惠券的不同计算策略,包括一个接口类(ICoupondiscount
)和四种优惠券的实现方式。最后提供了策略模式的上下控制类,用于处理整体的策略服务。
优惠券接口
1 2 3 4 5
| package com.bestrook.design; import java.math.BigDecimal; public interface ICouponDiscount<T> { BigDecimal discountAmount(T couponInfo,BigDecimal skuPrice); }
|
定义了优惠券接口,也增加了泛型,不同类型的接口可以传递不同的参数类型。接口包括商品金额以及出参返回优惠后金额。在实际开发中,会比现在的接口参数多一些,但核心逻辑类似。
优惠券接口实现
满减
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.bestrook.design.event; import com.bestrook.design.ICouponDiscount; import java.math.BigDecimal; import java.util.Map; public class MJCouponDiscount implements ICouponDiscount<Map<String, String>> { @Override public BigDecimal discountAmount(Map<String, String> couponInfo, BigDecimal skuPrice) { String x = couponInfo.get("x"); String o = couponInfo.get("o"); 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; } }
|
直减
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.bestrook.design.event; import com.bestrook.design.ICouponDiscount; import java.math.BigDecimal; public class ZJCouponDiscount implements ICouponDiscount<Double> { @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; } }
|
折扣
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.bestrook.design.event; import com.bestrook.design.ICouponDiscount; import java.math.BigDecimal; public class ZKCouponDiscount implements ICouponDiscount<Double> { @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; } }
|
N元购
1 2 3 4 5 6 7 8 9
| package com.bestrook.design.event; import com.bestrook.design.ICouponDiscount; import java.math.BigDecimal; public class NYGCouponDiscount implements ICouponDiscount<Double> { @Override public BigDecimal discountAmount(Double couponInfo, BigDecimal skuPrice) { return new BigDecimal(couponInfo); } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.bestrook.design; import com.bestrook.design.event.MJCouponDiscount; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; public class TestApi { public static void main(String[] args) { Context<Map<String, String>> mJContext = new Context<>(new MJCouponDiscount()); Map<String, String> mapReq = new HashMap<>(); mapReq.put("x","100"); mapReq.put("o","10"); System.out.println("减慢优惠:"+mJContext.discountAmount(mapReq,new BigDecimal(100)));
} }
|
总结
这个演示的策略模式并不复杂,主要的逻辑体现在不同种类优惠券的计算折扣策略上。在实际的开发中,这种设计模式很常用。另外这种设计模式与命令模式、适配器模式的结构相似,但是思路略有些差异。通过使用策略模式,可以优化方法中的if语句。在使用这种设计模式后,可以很好的满足隔离性和扩展性要求,也方便承接不断新增的需求。
策略模式、适配器模式和组合模式等在某些方面是比较相似的,但是每一种设计模式有自己的逻辑特点,在使用的过程中需要经过多次实践来体会,积累经验。