设计模式之策略模式实战讲解
出发点🚠
其实简单来说策略模式就是:再进行需求变更,业务演化过程时 能够新增代码去实现业务需求的变更 而不修改原来的代码——也就是说其要符合 开闭原则
何为开闭原则🧐
开放封闭原则(OCP,Open Closed Principle)作为设计模式六大原则之一,也是面向对象编程的核心:其本质就是说 :对扩展开放,对修改封闭
演示开闭原则学习👨🏭
控制层
kotlin
复制代码
@RestController public class CouponController { @Resource private CouponService couponService; @RequestMapping(value = "/getMoney",method = RequestMethod.GET) public BigDecimal getMoney() { return couponService.getDiscount(); } }
接口
csharp
复制代码
public interface CouponService { \** \* 获取优惠券金额 \* @return BigDecimal \* BigDecimal getMoney(); }
事务
java
复制代码
@Service\ public class CouponInterfaceImpl implements CouponService { /\*\*\ \* 折扣\ \*/\ private final BigDecimal discount = new BigDecimal("0.5"); @Override\ public BigDecimal getMoney() {\ return new BigDecimal(50).multiply(discount);\ }\ }
以上也是为了举一个例子 :
因为其实大家可能都知道 要定义一个接口 然后一个类去实现它 这样做
但是这样做 的意义是什么 可能大家就不是太清楚啦 只知道:噢!这是一个规范 那么我就应该去遵守它。
It's been a long time……
参加 需求分析评审:
然后你听到产品这样说:首先是一个折扣 再代码刚上线的时候 全场五折!
咔嚓咔嚓 你记下来这个需求~ 这里这样去写的~
然后 写完 你转头继续去写别的需求!
过了两天 说要和用户项目组那边协调 要查看用户的角色 再角色上进行校验
admin 账号 享有 公司员工折扣 vip 享有会员折扣 不充值vip 没有折扣😂~
typescript
复制代码
@Service\ public class CouponInterfaceImpl implements CouponService { \* \* 默认折扣 \* private BigDecimal discount = new BigDecimal("0.5"); @Override public BigDecimal getMoney(String role) { // 公司账号 管理员权限 享受员工价 if ("admin".equals(role)) { discount = new BigDecimal("0.4"); return new BigDecimal(50).multiply(discount); } // 开店充值会员 享受 会员价 if ("vip".equals(role)) { return new BigDecimal(50).multiply(discount); } // 其他账号 不参与折扣 return new BigDecimal(50); } }
然后你的代码 就变成了这样
过了几天 再继续开发
领导又说 不行不行 我们还要这样:
1、如果用户 违规次数 达到了5次 用户账号处于封禁状态 如果封禁状态的用户 无法购买
2、vip 可以进行月内5次 的折扣 svip 可以享受十次折扣 😂😂
然后就变成这样
typescript
复制代码
@Service public class CouponInterfaceImpl implements CouponService { \** \* 默认折扣 \* private BigDecimal discount = new BigDecimal("0.5"); @Resource private CouponMapper couponMapper; @Override public BigDecimal getMoney(String role) { if (!couponMapper.getStatus().equals("1")) { // todo 打印日志…… return null; } // todo 判断用户消费 -> 引入redis mysql // 公司账号 管理员权限 享受员工价 else { if ("admin".equals(role)) { discount = new BigDecimal("0.4"); return new BigDecimal(50).multiply(discount); } } // 开店充值会员 才能享受 会员价 if ("vip".equals(role)) { // 代码逻辑…… return new BigDecimal(50).multiply(discount); } // 其他账号 不参与折扣 return new BigDecimal(50); } }
其实这个时候 代码已经很乱了 正常来说 在上线时前 或者需求提测的时候 会有一个CR环节 也就是说Code Review
然后 你自己优化这段代码 如果你还不了解策略模式的话
可能就是想到的就是简单的 if-else 用一个三目运算符 去优化……
其他代码 比如长 if-else 去通过传入一个type 根据不同的type 比如type 1 为默认方案 type 2 为 xx方案
然后在这个类下 去实现不同的方法 根据type 调用方法
也就是说下面这样:
less
复制代码
\** \* {@code @name} demo \* {@code @description} \* \* @author <a href="https://github.com/lizhe-0423">荔枝程序员</a> \* {@code @data} 2024 2024/2/3 10:21 \* @Service public class CouponInterfaceImpl implements CouponService { /\*\*\ \* 默认折扣 \*/\ private final BigDecimal discount = new BigDecimal("0.5"); @Resource private CouponMapper couponMapper; @Override public BigDecimal getMoney(String role) { if (!couponMapper.getStatus().equals("1")) { // todo 打印日志…… return null; } switch (couponMapper.getType()) { case 1: return getMoneyType1(); case 2: return getMoneyType2(); case 3: return getMoneyType3(); case 4: return getMoneyType4(); default: return null; } } public BigDecimal getMoneyType1() { //默认的策略 return new BigDecimal(50); } public BigDecimal getMoneyType2() { // 拥有vip的用户 return new BigDecimal(25); } public BigDecimal getMoneyType3() { // 拥有admin 用户 return new BigDecimal(20); } public BigDecimal getMoneyType4() { // 其他用户但是为活跃账号 return new BigDecimal(30); } }
但是 其实这样 我们进行修改的时候还是会去动这个类本身 比如 当上线之后
马上还有一个月双十一
然后你的需求是:
可能会这样 双十一 发送专属双十一的限量10万张折扣券 (0.8折)
1、 折扣券可以和svip会员折扣重叠 但是无法和vip折扣重叠
2、折扣券可以和所有用户参与的专属活动获得的优惠券进行折叠消费
3、……
然后你说:累了毁灭吧 因为要通过封板 及 xx 联调等一系列各种情况 留给你开发时间可能也就 2-3天
当去修改这整个类的时候 就会发现if -else 分支 长到离谱……
策略模式+工厂模式🏹
更改我们的控制层
less
复制代码
@RestController public class CouponController { @Resource private List<CouponService> couponService; @RequestMapping(value = "/getMoney", method = RequestMethod.GET) public BigDecimal getMoney(@RequestParam Integer type) { if (type==null) { return null; } return Objects. requireNonNull(couponService.stream().filter(l -> l.isTypeTrue(type)).findFirst().orElse(null)).getMoney(); } }
其实就会发现 不同的实现类去代表着不同的策略
实现类内部如此定义:
typescript
复制代码
@Service public class CouponInterfaceType1Impl implements CouponService { @Override public boolean isTypeTrue(Integer type) { return type == 1; } @Override public BigDecimal getMoney() { //业务代码 return new BigDecimal(50); } }
这样 我们在不修改类 方法的同时 通过新增不同实现类 去实现不同的策略功能
演示效果🎨
type 为 1 表示 默认执行策略
type 为2 表示 会员折扣
希望本教程能够对大家有所帮助 (●'◡'●)