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

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

出发点🚠

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

何为开闭原则🧐

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

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

相关推荐
ProtonBase17 分钟前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
乐之者v23 分钟前
leetCode43.字符串相乘
java·数据结构·算法
suweijie7684 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿4 小时前
List深拷贝后,数据还是被串改
java
xlsw_7 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹8 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭9 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫9 小时前
泛型(2)
java
超爱吃士力架9 小时前
邀请逻辑
java·linux·后端
南宫生9 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论