上个月的双十一,这月的双十二,打折不断,优惠不停。电商系统中发放优惠券,是一个比较常见的功能。今天讲一个优惠券开发实战。
🍊需求
现在有一个需求,实现不同时间段发放不同优惠券,比如11.11日凌晨0~12点之间发放7折优惠券,12~18点之间发放8折优惠券,18~24点之间发放9折优惠券。
作为开发老油条,你会选用什么数据结构发放优惠券呢?
🍎功能分析
首选明确,这个需求里面有个区间概念,整理如下:
开始时间(含) | 结束时间(不含) | 优惠券 |
0 | 12 | 7折 |
12 | 18 | 8折 |
18 | 24 | 9折 |
数学表达:
[0, 12) ==> 7折
[12, 18) ==> 8折
[18, 12) ==> 9折
🍒数据结构选择
使用TreeMap
/** * the RangeTest * @author Java实用技术手册 * @date 2022-12-17 */publicclassRangeTest { privatestaticMap<Integer, String>discountMap=newTreeMap<>(); publicstaticvoidmain(String[] args) { initDiscountMap(); System.out.println("getDiscount_11="+getDiscount(11)); System.out.println("getDiscount_12="+getDiscount(12)); } publicstaticvoidinitDiscountMap() { discountMap.put(0, Discount.DISCOUNT_7); discountMap.put(12, Discount.DISCOUNT_8); discountMap.put(18, Discount.DISCOUNT_9); } publicstaticDiscountgetDiscount(Integertime) { Objects.requireNonNull(time); if (time>=0&&time<12) { returndiscountMap.get(0); } elseif (time>=12&&time<18) { returndiscountMap.get(12); } elseif (time>=18&&time<24) { returndiscountMap.get(18); } returnnull; } }
大致思路就是使用TreeMap分段设置,查找的时候,比较当前时间处于哪个区间,然后返回对应的value。
上面的代码包括initDiscountMap
和getDiscount
方法,可以看出如果要新增一个时间区间的优惠券,需同时修改这2个方法,违反了代码开闭原则。
使用Guava的TreeRangeMap
之前我们说谷歌神器Guava工具类的时候,提到过多种骚气的Map,其中TreeRangeMap就是一个为区间Map。
当前POM依赖
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency>
TreeRangeMap描述的是“不相交且非空的区间”到特定值的映射。
内部存储完美符合上面的数学表达式。
[0, 12) ==> 7折
[12, 18) ==> 8折
[18, 12) ==> 9折
使用方法: 先使用TreeRangeMap.create()
创建RangeMap,然后put数据。
key=Range(),value=折扣值。
其中:Range有多个方法,注意根据需求使用。
方法 | 左边 | 右边 | 数学表达 |
open | 开 | 开 | (a, b) |
closed | 闭 | 闭 | [a, b] |
closedOpen | 闭 | 开 | [a, b) |
openClosed | 开 | 闭 | (a, b] |
/** * the RangeTest * @author Java实用技术手册 * @date 2022-12-17 */publicclassRangeTest { privatestaticRangeMap<Integer, Discount>rangeMap=TreeRangeMap.create(); publicstaticvoidmain(String[] args) { initDiscountMapGuava(); System.out.println("getDiscountGuava_11="+getDiscountGuava(11)); System.out.println("getDiscountGuava_12="+getDiscountGuava(12)); } /** * 初始化RangeMap,注意key的区间开闭性。 */publicstaticvoidinitDiscountMapGuava() { rangeMap.put(Range.closedOpen(0, 12), Discount.DISCOUNT_7); rangeMap.put(Range.closedOpen(12, 18), Discount.DISCOUNT_8); rangeMap.put(Range.closedOpen(18, 24), Discount.DISCOUNT_9); } publicstaticDiscountgetDiscountGuava(Integertime) { returnrangeMap.get(Objects.requireNonNull(time)); } }
使用RangeMap后,新增一个时间区间优惠券,只要在初始化方法中增加一行数据,而且key的Range设计也比较符合人文理解。
对RangeMap的遍历,可以使用 Map<Range<K>, V> TreeRangeMap#asMapOfRanges()
方法。
以上就是本期内容,希望对你有帮助。
我是Pandas,专注Java编程实用技术分享,公众号《
Java实用技术手册
》和B站均有视频解说,欢迎来玩。如果你觉得这篇文章有用,别忘了点赞+关注,一起进步!