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

点击关注公众号,Java干货及时送达👇

一、为什么讲策略模式

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

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

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

二、经典策略模式

数据DTO

@Data  
public class Stock {  // 股票交易代码  private String code;  // 现价  private Double price;  // 涨幅  private Double rise;  
}

抽象得到的策略接口

public interface Strategy {  /**  * 将股票列表排序  *  * @param source 源数据  * @return 排序后的榜单  */  List<Stock> sort(List<Stock> source);  
}

实现我们的策略类

/**  * 高价榜  */  
public class HighPriceRank implements Strategy {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getPrice).reversed())  .collect(Collectors.toList());  }  
}  /**  * 低价榜  */  
public class LowPriceRank implements Strategy {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getPrice))  .collect(Collectors.toList());  }  
}  /**  * 高涨幅榜  */  
public class HighRiseRank implements Strategy {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getRise).reversed())  .collect(Collectors.toList());  }  
}

经典的Context类,

public class Context {  private Strategy strategy;  public void setStrategy(Strategy strategy) {  this.strategy = strategy;  }  public List<Stock> getRank(List<Stock> source) {  return strategy.sort(source);  }  
}

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

@Service  
public class RankServiceImpl {  /**  * dataService.getSource() 提供原始的股票数据  */  @Resource  private DataService dataService;  /**  * 前端传入榜单类型, 返回排序完的榜单  *  * @param rankType 榜单类型  * @return 榜单数据  */  public List<Stock> getRank(String rankType) {  // 创建上下文  Context context = new Context();  // 这里选择策略  switch (rankType) {  case "HighPrice":  context.setStrategy(new HighPriceRank());  break;  case "LowPrice":  context.setStrategy(new LowPriceRank());  break;  case "HighRise":  context.setStrategy(new HighRiseRank());  break;  default:  throw new IllegalArgumentException("rankType not found");  }  // 然后执行策略  return context.getRank(dataService.getSource());  }  
}

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

三、基于枚举的策略模式

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

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

枚举策略类

public enum RankEnum {  // 以下三个为策略实例  HighPrice {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getPrice).reversed())  .collect(Collectors.toList());  }  },  LowPrice {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getPrice))  .collect(Collectors.toList());  }  },  HighRise {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getRise).reversed())  .collect(Collectors.toList());  }  };  // 这里定义了策略接口  public abstract List<Stock> sort(List<Stock> source);  
}

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

@Service  
public class RankServiceImpl {  /**  * dataService.getSource() 提供原始的股票数据  */  @Resource  private DataService dataService;  /**  * 前端传入榜单类型, 返回排序完的榜单  *  * @param rankType 榜单类型 形似 RankEnum.HighPrice.name()  * @return 榜单数据  */  public List<Stock> getRank(String rankType) {  // 获取策略,这里如果未匹配会抛 IllegalArgumentException异常  RankEnum rank = RankEnum.valueOf(rankType);  // 然后执行策略  return rank.sort(dataService.getSource());  }  
}

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

  • 枚举的策略类是公用且静态,这意味着这个策略过程不能引入非静态的部分,扩展性受限

  • 策略模式的目标之一,是优秀的扩展性和可维护性,最好能新增或修改某一策略类时,对其他类是无改动的。而枚举策略如果过多或者过程复杂,维护是比较困难的,可维护性受限

四、基于工厂的策略模式

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

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

/**  * 高价榜  * 注意申明 Service.value = HighPrice,他是我们的key,下同  */  
@Service("HighPrice")  
public class HighPriceRank implements Strategy {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getPrice).reversed())  .collect(Collectors.toList());  }  
}  /**  * 低价榜  */  
@Service("LowPrice")  
public class LowPriceRank implements Strategy {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getPrice))  .collect(Collectors.toList());  }  
}  /**  * 高涨幅榜  */  
@Service("HighRise")  
public class HighRiseRank implements Strategy {  @Override  public List<Stock> sort(List<Stock> source) {  return source.stream()  .sorted(Comparator.comparing(Stock::getRise).reversed())  .collect(Collectors.toList());  }  
}

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

@Service  
public class RankServiceImpl {  /**  * dataService.getSource() 提供原始的股票数据  */  @Resource  private DataService dataService;  /**  * 利用注解@Resource和@Autowired特性,直接获取所有策略类  * key = @Service的value  */  @Resource  private Map<String, Strategy> rankMap;  /**  * 前端传入榜单类型, 返回排序完的榜单  *  * @param rankType 榜单类型 和Service注解的value属性一致  * @return 榜单数据  */  public List<Stock> getRank(String rankType) {  // 判断策略是否存在  if (!rankMap.containsKey(rankType)) {  throw new IllegalArgumentException("rankType not found");  }  // 获得策略实例  Strategy rank = rankMap.get(rankType);  // 执行策略  return rank.sort(dataService.getSource());  }  
}

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

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

感谢阅读,希望对你有所帮助 :)   

来源:toutiao.com/article/7080135241830302212

 
热门内容:
  • 面试官:一千万的数据,你是怎么查询的?

  • 公司入职一个阿里大佬,把 Spring Boot 系统启动时间从 7 分钟降到了 40 秒!

  • 简化 Hello World:Java 新写法要来了!!

  • 一款 IntelliJ IDEA 神级插件,由 ChatGPT 团队开发,堪称辅助神器!

 

9e786fb6a627fd4977c0217dc98eb168.jpeg

 
最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/59585.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023高校毕业生薪酬曝光,这才是90%应届生的工资真相?

随着全国高校应届毕业生总人数不断攀升&#xff0c;每年毕业季都号称就业形势最差&#xff0c;没有之一。 2023高校毕业生薪酬排行榜新鲜出炉&#xff0c;工资差距难免引起部分学生“心理不平衡”。在此之外&#xff0c;排行榜背后所透露的讯息&#xff0c;更值得我们关注。 …

高考开始了,计算机专业未来还会火吗?

2023年高考&#xff0c;今天开始第一场考试。而走出考场&#xff0c;考生们也将面临选报专业的难题。高考人数逐年攀升&#xff0c;录取率却不断下降。 过去10年&#xff0c;计算机专业可谓红透半边天&#xff0c;早早进入这个行业的&#xff0c;基本都吃到了很高的红利。然而…

100个国家的数字货币政策大全

近几年比特币的大涨和ICO市场的疯狂让数字货币逐渐的被越来越多的人所熟知。2017年9月4号中国对ICO的全面禁止也让人们意识到市场监管的必要性。然而各个国家对数字货币的态度和监管政策却相差甚远&#xff0c;有的国家全面严厉监管&#xff0c;有的国家打开国门主动拥... 近几…

做完GPT-4完整测评,微软爆火论文称初版AGI就快来了

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶” 重磅干货&#xff0c;第一时间送达 GPT-4 的能力什么档次&#xff1f; 1956 年&#xff0c;在达特茅斯学院召开的一个研讨会上&#xff0c;人工智能这一概念正式被提出。 之后这个词一直挑战着心理学家、哲…

2023智源大会议程公开 | 基于认知神经科学的大模型

2023年&#xff0c;人工智能新研究、新系统、新产品竞放——我们即将见证另一场有关智能的惊叹演化。6月9日&#xff0c;2023北京智源大会&#xff0c;将邀请这一领域的探索者、实践者、以及关心智能科学的每个人&#xff0c;共同拉开未来舞台的帷幕&#xff0c;你准备好了吗&a…

python3写360图库爬虫

前言 要求&#xff1a;进行搜索并且保存360图库图片 图库地址&#xff1a;360图库 基本思路 简单分析以后&#xff0c;发现360图库使用动态渲染&#xff0c;并且采用下拉反式加载图片&#xff0c;那么解决问题就出现3种常用方法&#xff0c;操作js、模拟浏览器、Ajax。如果使…

“一言”既出,谁与争峰:权威国际测评给文心大模型3.5打出满分,三项绝对第一领跑!...

国内百“模”大战下&#xff0c;究竟谁实力最强&#xff0c;全球领先的IT市场研究和咨询公司IDC最新发布的《AI大模型技术能力评估报告&#xff0c;2023》给出了答案。报告显示百度文心大模型3.5拿下12项指标的7个满分&#xff0c;综合评分第一&#xff0c;算法模型第一&#x…

三个月诞生79个基础大模型,企业选用大模型需要注意些什么?

自从ChatGPT横空出世&#xff0c;各类大模型层出不穷&#xff0c;竞争也日渐激烈&#xff0c;可谓“乱花渐欲迷人眼”。 随着大公司的入场&#xff0c;无疑给创业公司带来了降维打击&#xff0c;创业公司随时可能倒掉&#xff0c;造成项目烂尾。 我也一直在关注大模型领域的最…

知名插画师走尺,带你走进“薪”世界

如果你要问我&#xff0c;掌握一门技能难不难呢&#xff1f;说实话&#xff0c;我觉得只要足够热爱&#xff0c;苦也是甜。 回顾我刚工作那几年&#xff0c;很注重自己的个人成长&#xff0c;总是一头扎进学技能的热潮里&#xff0c;看到别人因为什么技能提升改变了自己&#…

写着代码的插画师—王凌 |WLOP|

王凌(wlop),出生于江苏苏州,毕业于香港大学工学院,是一名工程师,自学的数字艺术与插画。 个人主页: http://wlop.deviantart.com/ 微博id: wlop- 以下部分内容来自 /CHOK/ /幕青社/ wlop-微博截图 ▼ 或许有朋友知道这位《鬼刀》(ghost blade)漫画的作者。 高中时偶然在有妖…

csp怎么给线条描边,插画师要失业了?还在纠结阴影怎么画?CSP软件能直接自动生成...

原标题&#xff1a;插画师要失业了&#xff1f;还在纠结阴影怎么画&#xff1f;CSP软件能直接自动生成 阴影怎么画&#xff1f;CSP软件好用吗&#xff1f;板绘应该如何入门&#xff1f;如何成为插画师&#xff1f;学习绘画难吗&#xff1f;怎样才能学好绘画&#xff1f;想必这些…

插画师的配色灵感分享

插画师&#xff5c;vacuum_chan 甜酷暗黑配色&#xff1a; 对比度高 明度低 饱和度高 风格&#xff1a;暗黑 魔幻 甜酷 神秘 /作品从人物造型、配色上&#xff0c;都可以当作我们用来练习人物插画、场景插画的学习参考。

AI插画师:生成对抗网络

目录 7.1 GAN的原理简介 7.2 用GAN生成动漫头像 7.3 实验结果分析 生成对抗网络&#xff08;Generative Adversarial Net,GAN&#xff09;是近年来深度学习中一个十分热门的方向&#xff0c;卷积网络之父、深度学习元老级人物LeCun Yan就曾说过“GAN is the most interestin…

西班牙插画师 Alex Vede

西班牙插画师 Alex Vede 西班牙插画师 Alex Vede&#xff0c;用细碎的线条刻画出细节丰富的场景&#xff0c;却能让人感受到画面里满满的故事情节。 西班牙插画师 Alex Vede&#xff0c;用细碎的线条刻画出细节丰富的场景&#xff0c;却能让人感受到画面里满满的故事情节。 西…

兴趣变高薪副业,知名插画师走尺带你感受插画的魅力

随着9月份的临近&#xff0c;又有一批新生即将步入大学校园&#xff0c;不免让我想起暑期“女生考入清华美院校长送化妆包”话题引起网友热议。据悉&#xff0c;文化成绩优异的魏泽涵因不舍内心热爱&#xff0c;高二依然选择艺考&#xff0c;为追上其他艺术生同学&#xff0c;她…

插画师所需的基础软件

ps虽然功能很多&#xff0c;看起来很复杂的样子&#xff0c;但绘画的话&#xff0c;常用的就几个工具&#xff0c;不会的可以去b站搜专门针对绘画的ps教程。 PS笔刷&#xff1a;平时日常练习&#xff0c;ps自带的笔刷就够用了&#xff0c;工作中一般有特定的笔刷&#xff0c;主…

插画师所需的素材网站

NO.1字加网 简介&#xff1a;登陆即可免费下载网站所有字体&#xff0c;所有字体都可以免费个人使用&#xff0c;部分字体可以免费商用。主要是中文字体&#xff0c;少量泰文和日文字体&#xff0c;界面清晰&#xff0c;分类清楚&#xff0c;是非常不错的字体网站。 NO.2 Font…

商业插画师走尺印象:只为做生活的设计师

从“知识改变命运”到如今的“技能改变人生”&#xff0c;拥有一技之长显然已经成为当下人尽皆知的一个生存之道。掌握一门顺应时代发展的高含金量技能&#xff0c;不仅能够增加自己的财富&#xff0c;甚至可以改变自己的一生。 到7月底&#xff0c;我已经跟着走尺老师学习插画…

天津插画师培训机构 ,0基础可以学吗?

天津插画师培训机构 &#xff0c;0基础可以学吗&#xff1f; 其实很多0零基础同学在学和不学之间犹豫&#xff0c;大部分的原因是考虑学习插画难不难&#xff0c;自己能不能学的会&#xff1f;现在就告诉你&#xff0c;学习插画很简单&#xff0c;0基础同学也可以的&#xff0…

插画师配色分享

插画师&#xff5c;kun333r 梦幻配色&#xff1a; 对比度高 色相丰富 光泽感 风格&#xff1a;少女 厚涂 梦幻 浪漫 作品从人物造型、配色上&#xff0c;都可以当作我们用来练习厚涂插画、氛围感插画的学习参考。 “想要坠入深海里&#xff0c;独自去最深的海底。 还想…