设计模式之策略模式实战讲解

设计模式之策略模式实战讲解

出发点🚠

其实简单来说策略模式就是:再进行需求变更,业务演化过程时 能够新增代码去实现业务需求的变更 而不修改原来的代码------也就是说其要符合 开闭原则

何为开闭原则🧐

开放封闭原则(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 表示 会员折扣

希望本教程能够对大家有所帮助 (●'◡'●)

相关推荐
考虑考虑9 小时前
Jpa使用union all
java·spring boot·后端
用户37215742613510 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊11 小时前
Java学习第22天 - 云原生与容器化
java
渣哥12 小时前
原来 Java 里线程安全集合有这么多种
java
间彧13 小时前
Spring Boot集成Spring Security完整指南
java
间彧13 小时前
Spring Secutiy基本原理及工作流程
java
Java水解14 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆16 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学17 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole17 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端