设计模式之策略模式实战讲解
出发点🚠
其实简单来说策略模式就是:再进行需求变更,业务演化过程时 能够新增代码去实现业务需求的变更 而不修改原来的代码------也就是说其要符合 开闭原则
何为开闭原则🧐
开放封闭原则(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 表示 会员折扣
希望本教程能够对大家有所帮助 (●'◡'●)