电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

Spring 環(huán)境下實(shí)現(xiàn)策略模式的示例

瀏覽:97日期:2023-08-09 10:10:15

背景

最近在忙一個需求,大致就是給滿足特定條件的用戶發(fā)營銷郵件,但是用戶的來源有很多方式:從 ES 查詢的、從 csv 導(dǎo)入的、從 MongoDB 查詢….. 需求很簡單,但是怎么寫的優(yōu)雅,方便后續(xù)擴(kuò)展,就存在很多門道了。

我們的項(xiàng)目是基于 Spring Boot 開發(fā)的,因此這篇文章也會基于 Spring Boot 作為基礎(chǔ)框架,教你如何使用 Spring 依賴注入的特性,優(yōu)雅的實(shí)現(xiàn)策略模式。

1. 簡單粗暴

最簡單粗暴直接的方式莫過于 if...else… 了,偽代碼如下:

if(來源 == ES){ // TODO: ES Query}else if(來源 == CSV){ // TODO: Read CSV File}else if(來源 == MongoDB){ // TODO: MongoDB Query}

如果后面還需要從其他平臺獲取,那就在接著添加 else if...,這種方式固然簡單直接,但是當(dāng)后續(xù)擴(kuò)展的方式越來越多,相應(yīng)的if...else...也會越來越長,emmm….. 怎么說呢,黑貓白貓,能抓到老鼠的就是好貓。

2. 策略模式

在 Spring 環(huán)境下實(shí)現(xiàn)策略模式異常簡單,畢竟 Spring 提供的依賴注入簡直就是開發(fā)利器~

既然是策略模式,那么定義策略肯定是首當(dāng)其沖,策略我們使用枚舉實(shí)現(xiàn)最佳。

public enum GroupType { /** * 從 ES 查詢 */ ES, /** * 從 MongoDB 查詢 */ MONGODB, /** * 從 文件 讀取 */ FILE}

下一步,我們定義一個接口,用于抽象通用的功能。

public interface IGroupSelect { /** * 人群獲取方式 * * @return 人群選擇枚舉 */ GroupType type(); /** * 查詢滿足條件的用戶 * * @param groupQuery 查詢條件 * @return 滿足條件的用戶 */ default List<GroupUser> queryUser(GroupQuery groupQuery) { checkQueryCondition(groupQuery); return doQuery(groupQuery); } /** * 事前校驗(yàn)查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數(shù)異常 */ void checkQueryCondition(GroupQuery groupQuery) throws IllegalArgumentException; /** * 真正的查詢方法 * * @param groupQuery 查詢條件 * @return 滿足條件的用戶 */ List<GroupUser> doQuery(GroupQuery groupQuery);}

這一步,小伙伴們有沒有發(fā)現(xiàn)里面也包含了模板方法模式呢?

然后就是不同策略的具體實(shí)現(xiàn)了。

ES 策略

@Slf4j@Servicepublic class EsGroupSelect implements IGroupSelect { /** * 人群獲取方式 * * @return 人群選擇枚舉 */ @Override public GroupType type() { return GroupType.ES; } /** * 事前校驗(yàn)查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數(shù)異常 */ @Override public void checkQueryCondition(GroupQuery groupQuery) throws IllegalArgumentException { log.info('groupQuery = {}', groupQuery); } /** * 查詢滿足條件的用戶 * * @param groupQuery 查詢條件 * @return 滿足條件的用戶 */ @Override public List<GroupUser> doQuery(GroupQuery groupQuery) { List<GroupUser> result = new ArrayList<>(); // TODO: // 1. 復(fù)雜的 ES 查詢邏輯 // 2. 根據(jù)條件篩選滿足條件的用戶數(shù)據(jù) for (int i = 1; i <= 15; i++) { result.add(GroupUser.of('ES用戶' + i, i + '@es.com')); } return result; }} 文件策略

@Slf4j@Servicepublic class FileGroupSelect implements IGroupSelect { /** * 人群獲取方式 * * @return 人群選擇枚舉 */ @Override public GroupType type() { return GroupType.FILE; } /** * 事前校驗(yàn)查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數(shù)異常 */ @Override public void checkQueryCondition(GroupQuery groupQuery) throws IllegalArgumentException { log.info('groupQuery = {}', groupQuery); } /** * 查詢滿足條件的用戶 * * @param groupQuery 查詢條件 * @return 滿足條件的用戶 */ @Override public List<GroupUser> doQuery(GroupQuery groupQuery) { List<GroupUser> result = new ArrayList<>(); // TODO: // 1. 復(fù)雜的解析、讀文件 // 2. 根據(jù)條件篩選滿足條件的用戶數(shù)據(jù) for (int i = 1; i <= 3; i++) { result.add(GroupUser.of('文件讀取用戶' + i, i + '@file.com')); } return result; }} MongoDB 策略

@Slf4j@Servicepublic class MongoGroupSelect implements IGroupSelect { /** * 人群獲取方式 * * @return 人群選擇枚舉 */ @Override public GroupType type() { return GroupType.MONGODB; } /** * 事前校驗(yàn)查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數(shù)異常 */ @Override public void checkQueryCondition(GroupQuery groupQuery) throws IllegalArgumentException { log.info('groupQuery = {}', groupQuery); } /** * 查詢滿足條件的用戶 * * @param groupQuery 查詢條件 * @return 滿足條件的用戶 */ @Override public List<GroupUser> doQuery(GroupQuery groupQuery) { List<GroupUser> result = new ArrayList<>(); // TODO: // 1. 復(fù)雜的 MongoDB 查詢邏輯 // 2. 根據(jù)條件篩選滿足條件的用戶數(shù)據(jù) for (int i = 1; i <= 7; i++) { result.add(GroupUser.of('MongoDB用戶' + i, i + '@mongo.com')); } return result; }}

現(xiàn)在到了最后一步,就是如何通過 Spring 優(yōu)雅的實(shí)現(xiàn)策略模式的選擇呢?敲黑板,考試必考!

我們通過定義一個工廠類,然后使用 Spring 的依賴注入特性,可以注入一個接口的多個實(shí)現(xiàn),這里采用 List<IGroupSelect> 的形式注入,Spring 也支持通過 Map<String,IGroupSelect> 的形式注入,如果使用 Map 注入,那么 key 就是類名,小伙伴們自己也可以測試一下~

@Servicepublic class GroupSelectFactory { @Autowired private List<IGroupSelect> groupSelectList; /** * 根據(jù)人群類型選擇具體的實(shí)現(xiàn)類 * * @param type 人群類型 * @return 人群選擇具體實(shí)現(xiàn)類 */ public IGroupSelect getGroupSelect(GroupType type) { Optional<IGroupSelect> groupSelectOptional = groupSelectList.stream().filter(t -> t.type() == type).findAny(); return groupSelectOptional.orElseThrow(() -> new IllegalArgumentException('暫不支持該人群方式')); }}

最后寫個定時任務(wù)測試一下吧。

@Autowiredprivate GroupSelectFactory groupSelectFactory;/** * 模擬定時發(fā)送營銷郵件 */@Scheduled(cron = '0/10 * * * * ?')public void sendEmailTask() { List<SendEmailTask> taskList = new ArrayList<>(); for (GroupType groupType : GroupType.values()) { GroupQuery groupQuery = new GroupQuery('虛頭巴腦的 ' + groupType.name() + ' 查詢條件'); taskList.add(SendEmailTask.of(groupType, groupQuery)); } taskList.forEach(task -> { List<GroupUser> groupUsers = groupSelectFactory.getGroupSelect(task.getType()).queryUser(task.getQuery()); log.info('groupUsers = {}', groupUsers); });}@Data@NoArgsConstructor@AllArgsConstructor(staticName = 'of')static class SendEmailTask implements Serializable { private static final long serialVersionUID = -3461263089669779193L; private GroupType type; private GroupQuery query;}

觀察控制臺,看看日志輸出吧~

總結(jié)

本文使用策略模式實(shí)現(xiàn)不同人群的查詢,后續(xù)如果要增加短信、微信、釘釘?shù)南l(fā)送,是不是也可以用策略模式實(shí)現(xiàn)呢? 使用 Spring 的依賴注入特性,可以注入一個接口的多個實(shí)現(xiàn),很容易就實(shí)現(xiàn)了策略模式的選擇,這樣后續(xù)添加一種策略的時候,完全不需要改動主要邏輯,只需添加具體實(shí)現(xiàn)即可。 細(xì)心的小伙伴可以發(fā)現(xiàn),本文雖然是講策略模式,其實(shí)里面還包含了模板方法、工廠模式,多種設(shè)計(jì)模式的協(xié)同作戰(zhàn),食用味道更佳喲~

配套代碼:https://github.com/xkcoding/practice_demo/tree/master/strategy-design-pattern-in-spring

以上就是Spring 環(huán)境下實(shí)現(xiàn)策略模式的示例的詳細(xì)內(nèi)容,更多關(guān)于Spring 實(shí)現(xiàn)策略模式的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 常州翔天实验仪器厂-恒温振荡器-台式恒温振荡器-微量血液离心机 恒温恒湿箱(药品/保健品/食品/半导体/细菌)-兰贝石(北京)科技有限公司 | 硬齿面减速机[型号全],ZQ减速机-淄博久增机械 | 储气罐,真空罐,缓冲罐,隔膜气压罐厂家批发价格,空压机储气罐规格型号-上海申容压力容器集团有限公司 | 电梯乘运质量测试仪_电梯安全评估测试仪-武汉懿之刻 | LNG鹤管_内浮盘价格,上装鹤管,装车撬厂家-连云港赛威特机械 | 齿辊分级破碎机,高低压压球机,立式双动力磨粉机-郑州长城冶金设备有限公司 | 航空障碍灯_高中低光强航空障碍灯_民航许可认证航空警示灯厂家-东莞市天翔航天科技有限公司 | 塑料薄膜_PP薄膜_聚乙烯薄膜-常州市鑫美新材料包装厂 | 磁力去毛刺机_去毛刺磁力抛光机_磁力光饰机_磁力滚抛机_精密金属零件去毛刺机厂家-冠古科技 | ge超声波测厚仪-电动涂膜机-电动划格仪-上海洪富 | 艺术涂料_进口艺术涂料_艺术涂料加盟_艺术涂料十大品牌 -英国蒙太奇艺术涂料 | 办公室家具公司_办公家具品牌厂家_森拉堡办公家具【官网】 | 电伴热系统施工_仪表电伴热保温箱厂家_沃安电伴热管缆工业技术(济南)有限公司 | 水篦子|雨篦子|镀锌格栅雨水篦子|不锈钢排水篦子|地下车库水箅子—安平县云航丝网制品厂 | 背压阀|减压器|不锈钢减压器|减压阀|卫生级背压阀|单向阀|背压阀厂家-上海沃原自控阀门有限公司 本安接线盒-本安电路用接线盒-本安分线盒-矿用电话接线盒-JHH生产厂家-宁波龙亿电子科技有限公司 | 济南货架定做_仓储货架生产厂_重型货架厂_仓库货架批发_济南启力仓储设备有限公司 | 软文发布平台 - 云软媒网络软文直编发布营销推广平台 | 青岛侦探_青岛侦探事务所_青岛劝退小三_青岛婚外情取证-青岛王军侦探事务所 | 冲击式破碎机-冲击式制砂机-移动碎石机厂家_青州市富康机械有限公司 | 东莞螺丝|东莞螺丝厂|东莞不锈钢螺丝|东莞组合螺丝|东莞精密螺丝厂家-东莞利浩五金专业紧固件厂家 | 二手电脑回收_二手打印机回收_二手复印机回_硒鼓墨盒回收-广州益美二手电脑回收公司 | 污泥烘干机-低温干化机-工业污泥烘干设备厂家-焦作市真节能环保设备科技有限公司 | 铁艺,仿竹,竹节,护栏,围栏,篱笆,栅栏,栏杆,护栏网,网围栏,厂家 - 河北稳重金属丝网制品有限公司 山东太阳能路灯厂家-庭院灯生产厂家-济南晟启灯饰有限公司 | 对照品_中药对照品_标准品_对照药材_「格利普」高纯中药标准品厂家-成都格利普生物科技有限公司 澳门精准正版免费大全,2025新澳门全年免费,新澳天天开奖免费资料大全最新,新澳2025今晚开奖资料,新澳马今天最快最新图库 | 全自动包装机_灌装机生产厂家-迈驰包装设备有限公司 | 尚为传动-专业高精密蜗轮蜗杆,双导程蜗轮蜗杆,蜗轮蜗杆减速机,蜗杆减速机生产厂家 | 武汉不干胶印刷_标签设计印刷_不干胶标签印刷厂 - 武汉不干胶标签印刷厂家 | 品牌设计_VI设计_电影海报设计_包装设计_LOGO设计-Bacross新越品牌顾问 | 润滑油加盟_润滑油厂家_润滑油品牌-深圳市沃丹润滑科技有限公司 琉璃瓦-琉璃瓦厂家-安徽盛阳新型建材科技有限公司 | 电动车头盔厂家_赠品头盔_安全帽批发_山东摩托车头盔—临沂承福头盔 | 电磁铁_小型推拉电磁铁_电磁阀厂家-深圳市宗泰电机有限公司 | arch电源_SINPRO_开关电源_模块电源_医疗电源-东佑源 | 首页 - 张店继勇软件开发工作室 兰州UPS电源,兰州山特UPS-兰州万胜商贸 | 空气能采暖,热泵烘干机,空气源热水机组|设备|厂家,东莞高温热泵_正旭新能源 | 过滤器_自清洗过滤器_气体过滤器_苏州华凯过滤技术有限公司 | 小威小说网 - 新小威小说网 - 小威小说网小说搜索引擎 | 餐饮加盟网_特色餐饮连锁加盟店-餐饮加盟官网 | 电磁流量计厂家_涡街流量计厂家_热式气体流量计-青天伟业仪器仪表有限公司 | 聚丙烯酰胺PAM-聚合氯化铝PAC-絮凝剂-河南博旭环保科技有限公司 巨野电机维修-水泵维修-巨野县飞宇机电维修有限公司 | 衬氟止回阀_衬氟闸阀_衬氟三通球阀_衬四氟阀门_衬氟阀门厂-浙江利尔多阀门有限公司 | ETFE膜结构_PTFE膜结构_空间钢结构_膜结构_张拉膜_浙江萬豪空间结构集团有限公司 |