likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 4

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

出发点🚠

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

何为开闭原则🧐

开放封闭原则(OCP,Open Closed Principle)作为设计模式六大原则之一,也是面向对象编程的核心:其本质就是说 :对扩展开放,对修改封闭

演示开闭原则学习👨‍🏭

控制层

    @RestController  
    public class CouponController {  
        @Resource  
        private CouponService couponService;  
      
        @RequestMapping(value = "/getMoney",method = RequestMethod.GET)  
        public BigDecimal getMoney() {  
            return couponService.getDiscount();  
        }  
    }  

接口


public interface CouponService {
     \**
     \* 获取优惠券金额
     \* @return BigDecimal
     \*
    BigDecimal getMoney();
}

事务

@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 没有折扣😂~

@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 可以享受十次折扣 😂😂

然后就变成这样

@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 调用方法

也就是说下面这样:


 \**
 \* {@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 分支 长到离谱……

策略模式+工厂模式🏹

更改我们的控制层

@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();
    }
}

其实就会发现 不同的实现类去代表着不同的策略

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

实现类内部如此定义:

@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 表示 会员折扣

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

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