av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁技術文章
文章詳情頁

Spring 環境下實現策略模式的示例

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

背景

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

我們的項目是基于 Spring Boot 開發的,因此這篇文章也會基于 Spring Boot 作為基礎框架,教你如何使用 Spring 依賴注入的特性,優雅的實現策略模式。

1. 簡單粗暴

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

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

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

2. 策略模式

在 Spring 環境下實現策略模式異常簡單,畢竟 Spring 提供的依賴注入簡直就是開發利器~

既然是策略模式,那么定義策略肯定是首當其沖,策略我們使用枚舉實現最佳。

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); } /** * 事前校驗查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數異常 */ void checkQueryCondition(GroupQuery groupQuery) throws IllegalArgumentException; /** * 真正的查詢方法 * * @param groupQuery 查詢條件 * @return 滿足條件的用戶 */ List<GroupUser> doQuery(GroupQuery groupQuery);}

這一步,小伙伴們有沒有發現里面也包含了模板方法模式呢?

然后就是不同策略的具體實現了。

ES 策略

@Slf4j@Servicepublic class EsGroupSelect implements IGroupSelect { /** * 人群獲取方式 * * @return 人群選擇枚舉 */ @Override public GroupType type() { return GroupType.ES; } /** * 事前校驗查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數異常 */ @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. 復雜的 ES 查詢邏輯 // 2. 根據條件篩選滿足條件的用戶數據 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; } /** * 事前校驗查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數異常 */ @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. 復雜的解析、讀文件 // 2. 根據條件篩選滿足條件的用戶數據 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; } /** * 事前校驗查詢條件 * * @param groupQuery 查詢條件 * @throws IllegalArgumentException 參數異常 */ @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. 復雜的 MongoDB 查詢邏輯 // 2. 根據條件篩選滿足條件的用戶數據 for (int i = 1; i <= 7; i++) { result.add(GroupUser.of('MongoDB用戶' + i, i + '@mongo.com')); } return result; }}

現在到了最后一步,就是如何通過 Spring 優雅的實現策略模式的選擇呢?敲黑板,考試必考!

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

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

最后寫個定時任務測試一下吧。

@Autowiredprivate GroupSelectFactory groupSelectFactory;/** * 模擬定時發送營銷郵件 */@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;}

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

總結

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

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

以上就是Spring 環境下實現策略模式的示例的詳細內容,更多關于Spring 實現策略模式的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
主站蜘蛛池模板: 日本精品一区二区三区视频 | 国产精品69毛片高清亚洲 | 欧美淫片 | 国产伦精品一区二区三区四区视频 | 欧美在线视频二区 | 国产乱人伦精品一区二区 | 午夜视频一区二区三区 | 日韩二| 91久久精品一区二区二区 | 国产精品美女久久久 | 国产激情一区二区三区 | 亚洲成在线观看 | 欧美中文字幕 | 在线播放中文字幕 | 日韩av免费看 | 精品视频www| 99精品电影 | 激情av网站 | 久草热线 | 午夜免费看| 日本久久网 | 亚洲国产精品人人爽夜夜爽 | 精品亚洲一区二区三区 | 成年人在线播放 | 精品国产乱码久久久久久蜜柚 | 瑟瑟视频在线看 | 91黄色片免费看 | av在线播放一区二区 | 九九热精品免费 | 中文字幕欧美一区二区 | 亚洲综合在线视频 | 中文字幕亚洲区一区二 | 国产精品99久久久久久动医院 | 欧美a在线观看 | 在线伊人| 亚洲午夜在线 | 97影院2| www.888www看片| 国内精品在线视频 | 免费不卡视频 | 一区二区国产精品 |