NipGeihou's blog NipGeihou's blog
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档

NipGeihou

我见青山多妩媚,料青山见我应如是
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档
  • 设计模式

    • 介绍与目的
    • 七大设计模式
    • 面向对象编程范式
    • 创造者模式
    • 创建者模式-单例模式
    • 创建者模式-工厂模式
    • 创建者模式-抽象工厂模式
    • 创建者模式-建造者模式
    • 创建者模式-原型模式
    • 结构型模式
    • 代理模式
    • 中介者模式
    • 命令模式
    • 责任链模式
    • 装饰模式
    • 策略模式
      • 概念
      • 使用场景
      • 角色
      • 代码示例
        • 需求
        • 优化前代码
        • 优化后代码
        • 总结
      • 参考资料
    • 适配器模式
    • 迭代器模式
    • 组合模式
    • 观察者模式
    • 外观模式
    • 备忘录模式
    • 访问者模式
    • 状态模式
    • 解释器模式
    • 享元模式
    • 桥接模式
    • 模板方法模式
  • 开发规范

  • 经验分享

  • 记录

  • 快速开始

  • 笔记

  • 面试题

  • 微服务

  • 踩过的坑

  • Java
  • 设计模式
NipGeihou
2022-09-01
目录

策略模式

# 概念

定义一组算法,将 ** 每个算法都封装起来,** 并且使它们之间可以互换。

# 使用场景

  • 多个类只有在算法或行为上稍有不同的场景。
  • 算法需要自由切换的场景。
  • 需要屏蔽算法规则的场景。
  • 具体策略数量超过 4 个,则需要考虑使用混合模式。

# 角色

  • 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

# 代码示例

# 需求

要做一个营销,需要用户参与一个活动,然后完成一系列的任务,最后可以得到一些奖励作为回报。活动的奖励包含美团外卖、酒旅和美食等多种品类券。

# 优化前代码

// 奖励服务
class RewardService {

    // 外部服务
    private WaimaiService waimaiService;
    private HotelService hotelService;
    private FoodService foodService;

    // 使用对入参的条件判断进行发奖
    public void issueReward(String rewardType, Object... params) {
        if ("Waimai".equals(rewardType)) {
            WaimaiRequest request = new WaimaiRequest();
            // 构建入参
            request.setWaimaiReq(params);
            waimaiService.issueWaimai(request);
        } else if ("Hotel".equals(rewardType)) {
            HotelRequest request = new HotelRequest();
            request.addHotelReq(params);
            hotelService.sendPrize(request);
        } else if ("Food".equals(rewardType)) {
            FoodRequest request = new FoodRequest(params);
            foodService.getCoupon(request);
        } else {
            throw new IllegalArgumentException("rewardType error!");
        }
    }
}

存在问题:

  1. 不符合开闭原则,可以预见,如果后续新增品类券的话,需要直接修改主干代码,而我们提倡代码应该是对修改封闭的;
  2. 不符合迪米特法则,发奖逻辑和各个下游接口高度耦合,这导致接口的改变将直接影响到代码的组织,使得代码的可维护性降低。

# 优化后代码

策略模式 + 适配器模式

// 策略接口
interface Strategy {
    void issue(Object... params);
}

// 外卖策略
class Waimai implements Strategy {

    private WaimaiService waimaiService;

    @Override
    public void issue(Object... params) {
        WaimaiRequest request = new WaimaiRequest();
        // 构建入参
        request.setWaimaiReq(params);
        waimaiService.issueWaimai(request);
    }
}

// 酒旅策略
class Hotel implements Strategy {

    private HotelService hotelService;

    @Override
    public void issue(Object... params) {
        HotelRequest request = new HotelRequest();
        request.addHotelReq(params);
        hotelService.sendPrize(request);
    }
}

// 美食策略
class Food implements Strategy {

    private FoodService foodService;

    @Override
    public void issue(Object... params) {
        FoodRequest request = new FoodRequest(params);
        foodService.payCoupon(request);
    }
}
// 使用分支判断获取的策略上下文
class StrategyContext {
    public static Strategy getStrategy(String rewardType) {
        switch (rewardType) {
            case "Waimai":
                return new Waimai();
            case "Hotel":
                return new Hotel();
            case "Food":
                return new Food();
            default:
                throw new IllegalArgumentException("rewardType error!");
        }
    }
}

// 优化后的策略服务
class RewardService {
    public void issueReward(String rewardType, Object... params) {
        Strategy strategy = StrategyContext.getStrategy(rewardType);
        strategy.issue(params);
    }
}

注意

这里只表达了有无使用策略模式的区别,并非最优代码,代码仍可进一步优化,具体优化细节可参考参考资料。

# 总结

从原代码可知,对于各品类的操作宏观上都是 入参 -> 放发 ,但微观的代码上又不一样。

// 外卖
WaimaiRequest request = new WaimaiRequest();
request.setWaimaiReq(params);
waimaiService.issueWaimai(request);

// 酒店
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);

// 美食
FoodRequest request = new FoodRequest(params);
foodService.getCoupon(request);

# 参考资料

  1. 嘉凯。杨柳。设计模式二三事 [EB/OL]. [2022-09-07]. https://tech.meituan.com/2022/03/10/interesting-talk-about-design-patterns.html (opens new window).
  2. baiyuxuan. 在 SpringBoot 中优雅地实现策略模式 [EB/OL]. 2021-11-28 [2023-9-12]. https://juejin.cn/post/7035414939657306126.
上次更新: 2023/09/13, 13:25:19
装饰模式
适配器模式

← 装饰模式 适配器模式→

最近更新
01
iSCSI服务搭建
05-10
02
磁盘管理与文件系统
05-02
03
网络测试 - iperf3
05-02
更多文章>
Theme by Vdoing | Copyright © 2018-2025 NipGeihou | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式