0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为什么我不再推荐枚举策略模式?

jf_ro2CN3Fa 来源:芋道源码 2023-04-14 10:52 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群


一、为什么讲策略模式

策略模式,应该是工作中比较常用的设计模式,调用方自己选择用哪一种策略完成对数据的操作,也就是“一个类的行为或其算法可以在运行时更改”

我个人的理解是 将一些除了过程不同其他都一样的函数封装成策略,然后调用方自己去选择想让数据执行什么过程策略。常见的例子为根据用户分类推荐不同的排行榜(用户关注点不一样,推荐榜单就不一样)

和单例模式一样,随着时间发展,我不再推荐经典策略模式,更推荐简单策略用枚举策略模式,复杂地用工厂策略模式。下面引入一个例子,我们的需求是:对一份股票数据列表,给出低价榜、高价榜、涨幅榜。这其中只有排序条件的区别,比较适合作为策略模式的例子

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

二、经典策略模式

数据DTO

@Data
publicclassStock{

//股票交易代码
privateStringcode;

//现价
privateDoubleprice;

//涨幅
privateDoublerise;
}

抽象得到的策略接口

publicinterfaceStrategy{

/**
*将股票列表排序
*
*@paramsource源数据
*@return排序后的榜单
*/
Listsort(Listsource);
}

实现我们的策略类

/**
*高价榜
*/
publicclassHighPriceRankimplementsStrategy{

@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getPrice).reversed())
.collect(Collectors.toList());
}
}

/**
*低价榜
*/
publicclassLowPriceRankimplementsStrategy{

@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getPrice))
.collect(Collectors.toList());
}
}

/**
*高涨幅榜
*/
publicclassHighRiseRankimplementsStrategy{

@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getRise).reversed())
.collect(Collectors.toList());
}
}

经典的Context类,

publicclassContext{
privateStrategystrategy;

publicvoidsetStrategy(Strategystrategy){
this.strategy=strategy;
}

publicListgetRank(Listsource){
returnstrategy.sort(source);
}
}

于是 我们顺礼成章地得到调用类--榜单实例RankServiceImpl

@Service
publicclassRankServiceImpl{

/**
*dataService.getSource()提供原始的股票数据
*/
@Resource
privateDataServicedataService;

/**
*前端传入榜单类型,返回排序完的榜单
*
*@paramrankType榜单类型
*@return榜单数据
*/
publicListgetRank(StringrankType){
//创建上下文
Contextcontext=newContext();
//这里选择策略
switch(rankType){
case"HighPrice":
context.setStrategy(newHighPriceRank());
break;
case"LowPrice":
context.setStrategy(newLowPriceRank());
break;
case"HighRise":
context.setStrategy(newHighRiseRank());
break;
default:
thrownewIllegalArgumentException("rankTypenotfound");
}
//然后执行策略
returncontext.getRank(dataService.getSource());
}
}

我们可以看到经典方法,创建了一个接口、三个策略类,还是比较啰嗦的。调用类的实现也待商榷,新增一个策略类还要修改榜单实例(可以用抽象工厂解决,但是复杂度又上升了)。加之我们有更好的选择,所以此处不再推荐经典策略模式

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

三、基于枚举的策略模式

这里对这种简单的策略,推荐用枚举进行优化。枚举的本质是创建了一些静态类的集合。

我下面直接给出例子,大家可以直观感受一下

枚举策略类

publicenumRankEnum{
//以下三个为策略实例
HighPrice{
@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getPrice).reversed())
.collect(Collectors.toList());
}
},
LowPrice{
@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getPrice))
.collect(Collectors.toList());
}
},
HighRise{
@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getRise).reversed())
.collect(Collectors.toList());
}
};

//这里定义了策略接口
publicabstractListsort(Listsource);
}

对应的调用类也得以优化,榜单实例RankServiceImpl

@Service
publicclassRankServiceImpl{

/**
*dataService.getSource()提供原始的股票数据
*/
@Resource
privateDataServicedataService;

/**
*前端传入榜单类型,返回排序完的榜单
*
*@paramrankType榜单类型形似RankEnum.HighPrice.name()
*@return榜单数据
*/
publicListgetRank(StringrankType){
//获取策略,这里如果未匹配会抛IllegalArgumentException异常
RankEnumrank=RankEnum.valueOf(rankType);
//然后执行策略
returnrank.sort(dataService.getSource());
}
}

可以看到,如果策略简单的话,基于枚举的策略模式优雅许多,调用方也做到了0修改,但正确地使用枚举策略模式需要额外考虑以下几点。

  • 枚举的策略类是公用且静态,这意味着这个策略过程不能引入非静态的部分,扩展性受限
  • 策略模式的目标之一,是优秀的扩展性和可维护性,最好能新增或修改某一策略类时,对其他类是无改动的。而枚举策略如果过多或者过程复杂,维护是比较困难的,可维护性受限

四、基于工厂的策略模式

为了解决良好的扩展性和可维护性,我更推荐以下利用spring自带beanFactory的优势,实现一个基于工厂的策略模式。

策略类改动只是添加了@Service注解,并指定了Service的value属性

/**
*高价榜
*注意申明Service.value=HighPrice,他是我们的key,下同
*/
@Service("HighPrice")
publicclassHighPriceRankimplementsStrategy{

@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getPrice).reversed())
.collect(Collectors.toList());
}
}

/**
*低价榜
*/
@Service("LowPrice")
publicclassLowPriceRankimplementsStrategy{

@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getPrice))
.collect(Collectors.toList());
}
}

/**
*高涨幅榜
*/
@Service("HighRise")
publicclassHighRiseRankimplementsStrategy{

@Override
publicListsort(Listsource){
returnsource.stream()
.sorted(Comparator.comparing(Stock::getRise).reversed())
.collect(Collectors.toList());
}
}

调用类修改较大,接入借助spring工厂特性,完成策略类

@Service
publicclassRankServiceImpl{

/**
*dataService.getSource()提供原始的股票数据
*/
@Resource
privateDataServicedataService;
/**
*利用注解@Resource@Autowired特性,直接获取所有策略类
*key=@Service的value
*/
@Resource
privateMaprankMap;

/**
*前端传入榜单类型,返回排序完的榜单
*
*@paramrankType榜单类型和Service注解的value属性一致
*@return榜单数据
*/
publicListgetRank(StringrankType){
//判断策略是否存在
if(!rankMap.containsKey(rankType)){
thrownewIllegalArgumentException("rankTypenotfound");
}
//获得策略实例
Strategyrank=rankMap.get(rankType);
//执行策略
returnrank.sort(dataService.getSource());
}
}

若读者使用的不是Spring,也可以找找对应框架的工厂模式实现,或者自己实现一个抽象工厂。

工厂策略模式会比枚举策略模式啰嗦,但也更加灵活、易扩展性和易维护。故简单策略推荐枚举策略模式,复杂策略才推荐工厂策略模式。



审核编辑 :李倩



声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 框架
    +关注

    关注

    0

    文章

    404

    浏览量

    18317
  • 函数
    +关注

    关注

    3

    文章

    4406

    浏览量

    66841

原文标题:为什么我不再推荐枚举策略模式?

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    远程办公防线不 “失守”,终端防护策略全解析

    随着企业日益拥抱远程与混合办公模式,如何有效保护所有远程终端已成为核心关切。终端安全策略因此成为关键——企业需要建立明确的规范与规则,在保障远程设备安全的同时,不影响工作效率。在自带设备(BYOD
    的头像 发表于 12-02 17:04 201次阅读
    远程办公防线不 “失守”,终端防护<b class='flag-5'>策略</b>全解析

    双转换VS生态模式:UPS工作原理深度对比与能效优化策略

    支持。今天,我们就来聊聊UPS的两种主流工作模式——双转换模式和生态模式,看看它们各自有什么特点,以及如何优化UPS的能效。一、双转换模式:电力纯净的“守护者”1.
    的头像 发表于 09-26 08:44 539次阅读
    双转换VS生态<b class='flag-5'>模式</b>:UPS工作原理深度对比与能效优化<b class='flag-5'>策略</b>

    Redis Sentinel和Cluster模式如何选择

    十年的运维生涯中,见过太多团队在Redis集群方案选择上踩坑。有的团队盲目追求"高大上"的Cluster模式,结果运维复杂度爆表;有的团队死守Sentinel不放,最后扩展性成了瓶颈。今天,想通过这篇万字长文,把
    的头像 发表于 09-08 09:31 375次阅读

    司受邀参加第八届电动工具控制与充电技术研讨会(苏州)暨清洁电器技术创新论坛--【其利天下】

    8月22日,第八届电动工具控制与充电技术研讨会(苏州)暨清洁电器技术创新论坛在苏州成功举办。司应Big-Bit大比特商务网邀请出席本次活动,并由研发总监冯建武先生带来题为《方弦一体控制策略
    的头像 发表于 08-22 18:07 6229次阅读
    <b class='flag-5'>我</b>司受邀参加第八届电动工具控制与充电技术研讨会(苏州)暨清洁电器技术创新论坛--【其利天下】

    CCG3PA是否支持发起BIST 共享容量消息?

    正在使用CCG3PA ,想发起BIST 共享容量消息。检查了 CCG3PA 的 API 文档和 PD 堆栈,但找不到任何与启动BIST 共享容量模式相关的
    发表于 07-23 07:07

    双三相感应电机SVPWM的新型过调制策略

    摘要:过调制策略能够提高逆变器输出电压范围和品质,从而提高电机输出转速范围和转矩特性。针对双三相感应电机空间矢量脉宽调制(SVPWM)算法过调制区域有限,分区实现复杂,内存占用率大等问题,提出一种
    发表于 06-19 11:10

    普通整流桥失效模式大解析:短路、过热与浪涌冲击应对策略

    实际工程角度出发,解析普通整流桥的常见失效模式——短路、过热与浪涌冲击,并提供相应的应对策略,帮助工程师实现更可靠的整流电路设计。一、失效模式一:整流桥短路短路是整流桥
    的头像 发表于 06-13 09:48 963次阅读
    普通整流桥失效<b class='flag-5'>模式</b>大解析:短路、过热与浪涌冲击应对<b class='flag-5'>策略</b>

    轮毂电机HEV能量管理策略优化研究

    纯分享帖,需要者可点击附件免费获取完整资料~~~*附件:轮毂电机HEV能量管理策略优化研究.pdf【免责声明】本文系网络转载,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请第一时间告知,删除内容!
    发表于 06-10 13:16

    如何重新启动 FX3S 的枚举过程?

    。 然而,面临的一个问题是,如果 FX3S 最初没有连接到 USB 3.0 电缆和 PC,它就不会重新启动枚举过程。 在这种情况下,有人能指导如何重新启动 FX3S 的枚举过程吗?
    发表于 05-19 07:34

    2.0 USB集线器CYUSB2304-68LTXI在重新枚举全速设备时出现错误怎么解决?

    刚刚构建的设计中有几个 USB 2.0 集线器 (CYUSB2304-68LTXI)。 每个集线器都连接有多个全速蓝牙设备。 当我重新枚举其中一个全速设备时,每次重新枚举都会得到超过 600 个
    发表于 05-19 07:32

    是德示波器DSOX3012A滚动模式设置指南

    、参数优化策略及典型应用场景,帮助用户高效掌握这一功能,提升信号分析效率。   一、滚动模式的基本原理与优势 滚动模式通过连续捕获并左移波形数据,在示波器屏幕上形成“时间轴窗口”,实现信号随时间变化的动态可视化。与传统触发
    的头像 发表于 05-13 15:55 502次阅读
    是德示波器DSOX3012A滚动<b class='flag-5'>模式</b>设置指南

    电机大范围调速的综合电压调制策略

    针对电动汽车要求驱动电机具有大范围调速要求和目前任何单种基本调制方式都无法做到全调制比范围内性能最优的问题,提出了一种综合的调制策略:在低调制比阶段使用传统的SVPWM策略,在高调制比阶段
    发表于 04-01 14:51

    永磁同步电机矢量控制策略分析

    本文通过矢量控制策略采用 id=0 控制方案快速准确地控制转矩,实现调速系统具有较高的动态性能。并利用了 Matlab 工具对永磁同步电机矢量控制系统在空载起动、转速突变、负载突变进行了仿真研究。 点击附件可直接打开查看全文*附件:永磁同步电机矢量控制策略分析.docx
    发表于 03-20 12:57

    渊亭KGAG升级引入“高级策略推理”

    为了突破现有AI技术在决策推理方面的局限,渊亭科技对其知识图谱分析平台KGAG进行了最新升级,创新性地引入了“高级策略推理”模式。这一模式的引入,实现了“大模型×知识图谱×专家策略×动
    的头像 发表于 02-14 15:07 807次阅读

    设计模式-策略模式

    作者:京东工业 孙磊 一、概念 策略模式(Strategy Pattern)也称为(Policy Parttern)。 它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变换
    的头像 发表于 01-08 13:47 555次阅读
    设计<b class='flag-5'>模式</b>-<b class='flag-5'>策略</b><b class='flag-5'>模式</b>