【抽象策略模式】實踐

前言

剛果商城,用戶登錄 Or 注冊 發送郵箱驗證碼場景,使用抽象策略模式實現

什么是抽象策略模式

抽象策略模式是一種行為型設計模式,它允許定義一系列算法,將每個算法封裝起來,并使它們可以互相替換。這使得客戶端代碼可以獨立于具體的算法實現而變化。

該模式主要包含三個角色。

三個角色

  1. 策略接口(Strategy Interface): 定義了一組算法的接口,具體的策略類實現這個接口,以便可以在上下文中互相替換。
  2. 具體策略類(Concrete Strategies): 實現了策略接口的具體算法。
  3. 上下文(Context): 包含一個對策略接口的引用,可以在運行時切換不同的策略。上下文通常包含一個方法,該方法使用策略接口調用具體的算法。

類圖

image-20231208162907587

首先

image-20231208141620007

策略執行抽象接口(策略接口)

/*** 策略執行抽象*/
public interface AbstractExecuteStrategy<REQUEST, RESPONSE> {/*** 執行策略標識*/String mark();/*** 執行策略** @param requestParam 執行策略入參*/default void execute(REQUEST requestParam) {}/*** 執行策略,帶返回值** @param requestParam 執行策略入參* @return 執行策略后返回值*/default RESPONSE executeResp(REQUEST requestParam) {return null;}
}

策略選擇器(上下文)

/*** 策略選擇器*/
public class AbstractStrategyChoose implements ApplicationListener<ApplicationInitializingEvent> {/*** 執行策略集合*/private final Map<String, AbstractExecuteStrategy> abstractExecuteStrategyMap = new HashMap<>();/*** 根據 mark 查詢具體策略** @param mark 策略標識* @return 實際執行策略*/public AbstractExecuteStrategy choose(String mark) {return Optional.ofNullable(abstractExecuteStrategyMap.get(mark)).orElseThrow(() -> new ServiceException(String.format("[%s] 策略未定義", mark)));}/*** 根據 mark 查詢具體策略并執行** @param mark         策略標識* @param requestParam 執行策略入參* @param <REQUEST>    執行策略入參范型*/public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam) {AbstractExecuteStrategy executeStrategy = choose(mark);executeStrategy.execute(requestParam);}/*** 根據 mark 查詢具體策略并執行,帶返回結果** @param mark         策略標識* @param requestParam 執行策略入參* @param <REQUEST>    執行策略入參范型* @param <RESPONSE>   執行策略出參范型* @return*/public <REQUEST, RESPONSE> RESPONSE chooseAndExecuteResp(String mark, REQUEST requestParam) {AbstractExecuteStrategy executeStrategy = choose(mark);return (RESPONSE) executeStrategy.executeResp(requestParam);}// 項目初始化時,會執行該方法,將所有策略對象都置于map集合中【key是mark標識(子類自行實現)】@Overridepublic void onApplicationEvent(ApplicationInitializingEvent event) {Map<String, AbstractExecuteStrategy> actual = ApplicationContextHolder.getBeansOfType(AbstractExecuteStrategy.class);actual.forEach((beanName, bean) -> {AbstractExecuteStrategy beanExist = abstractExecuteStrategyMap.get(bean.mark());if (beanExist != null) {throw new ServiceException(String.format("[%s] Duplicate execution policy", bean.mark()));}abstractExecuteStrategyMap.put(bean.mark(), bean);});}
}

登錄/注冊發送郵箱策略(具體策略類)

抽象公共郵箱驗證碼發送(公共邏輯)

將公共發郵箱的代碼抽象為一個類,便于復用

public abstract class AbstractMailVerifySender {@Value("${customer.user.register.verify.sender}")private String sender;@Value("${customer.user.register.verify.template-id}")private String templateId;@Resourceprivate MessageSendRemoteService messageSendRemoteService;@Resourceprivate DistributedCache distributedCache;/*** 用戶注冊驗證碼超時時間*/private static final long REGISTER_USER_VERIFY_CODE_TIMEOUT = 300000;/*** 獲取緩存前綴 Key*/protected abstract String getCachePrefixKey();/*** 郵箱驗證發送*/public void mailVerifySend(UserVerifyCodeCommand requestParam) {String verifyCode = RandomUtil.randomNumbers(6);// 模板方法模式: 驗證碼放入緩存,并設置超時時間distributedCache.put(CacheUtil.buildKey(getCachePrefixKey(), requestParam.getReceiver()), verifyCode, REGISTER_USER_VERIFY_CODE_TIMEOUT);MailSendRemoteCommand remoteCommand = new MailSendRemoteCommand();remoteCommand.setTitle("剛果商城郵箱驗證碼提醒").setReceiver(requestParam.getReceiver()).setSender(sender).setTemplateId(templateId).setParamList(Lists.newArrayList(verifyCode));messageSendRemoteService.mailMessageSend(remoteCommand);}
}

登錄注冊策略分別繼承 AbstractMailVerifySender 抽象類和實現 AbstractExecuteStrategy 抽象策略接口

image-20231208140223756

image-20231208140257567

登錄策略

@Component
public class MailLoginVerifyCommandHandler extends AbstractMailVerifySender implements AbstractExecuteStrategy<UserVerifyCodeCommand, Void> {@Overridepublic String mark() {return "customer_user_login_verify_mail";}// 直接調用父抽象類中方法即可 【核心代碼】@Overridepublic void execute(UserVerifyCodeCommand requestParam) {mailVerifySend(requestParam);}@Overrideprotected String getCachePrefixKey() {return CacheConstant.LOGIN_USER_VERIFY_CODE;}
}

注冊策略

@Component
@RequiredArgsConstructor
public class MailRegisterVerifyCommandHandler extends AbstractMailVerifySender implements AbstractExecuteStrategy<UserVerifyCodeCommand, Void> {@Overridepublic String mark() {return "customer_user_register_mail";}@Overridepublic void execute(UserVerifyCodeCommand requestParam) {mailVerifySend(requestParam);}@Overrideprotected String getCachePrefixKey() {return CacheConstant.REGISTER_USER_VERIFY_CODE;}
}

登錄注冊邏輯僅需各自定義mark標識以及對應存儲redis驗證碼的key前綴即可,代碼簡潔清爽、十分優雅。

接口調用

image-20231208140740829

入參:

@Data
@ApiModel("用戶驗證碼")
public class UserVerifyCodeCommand {@ApiModelProperty(value = "驗證類型", notes = "登錄驗證碼,注冊認證驗證碼等", example = "customer_user_login_verify")private String type;@ApiModelProperty(value = "驗證平臺", notes = "手機短信,郵箱,電話等", example = "mail")private String platform;@NotBlank(message = "接收者不能為空")@ApiModelProperty(value = "接收者", example = "m7798432@163.com", notes = "實際發送時更改為自己郵箱")private String receiver;
}

type + platform 拼接為對應策略mark(與調用策略mark對應上),根據策略上下文獲取對應策略執行邏輯即可。

策略選擇執行

    @Overridepublic void verifyCodeSend(UserVerifyCodeCommand requestParam) {String mark = requestParam.getType() + "_" + requestParam.getPlatform();// 策略模式: 根據 mark 選擇用戶登錄或者注冊邏輯abstractStrategyChoose.chooseAndExecute(mark, requestParam);}public <REQUEST> void chooseAndExecute(String mark, REQUEST requestParam) {AbstractExecuteStrategy executeStrategy = choose(mark);// 執行策略核心代碼executeStrategy.execute(requestParam);}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/208632.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/208632.shtml
英文地址,請注明出處:http://en.pswp.cn/news/208632.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java_LinkedList鏈表詳解

目錄 前言 ArrayList的缺陷 鏈表 鏈表的概念及結構 鏈表的種類 1.單向或雙向 2.帶頭或不帶頭 3.循環或不循環 LinkedList的使用 什么是LinkedList LinkedList的使用 LinkedList的構造 LinkedList的其他常用方法介紹 LinkedList的遍歷 ArrayList和LinkedList的…

OpenCL學習筆記(四)手動編譯開發庫(ubuntu+gcc+rk3588)

前言 筆者本次使用的是RK3588的開發板&#xff0c;內部燒寫的是ubuntu20.04&#xff0c;gcc版本是9 本文檔簡單記錄下編譯的過程&#xff0c;有需要的小伙伴可以參考下 一、安裝所需軟件 1.安裝git&#xff0c;教程比較多&#xff0c;不再重復 2.安裝cmake&#xff0c;教程…

UWB的matlab仿真源碼

作品詳細文章與下載鏈接 第一部分:TR-UWB信號的產生和調制 簡介 該實踐涉及使用 MATLAB 生成和調制 TR-UWB 信號。超寬帶信號是一類在頻譜中具有寬帶而不是窄帶的信號信號&#xff0c;具有時間寬度的脈沖產生它。在本次實踐中,MATLAB 程序是開發用于生成基帶 TR-UWB 信號,我們用…

在Windows電腦上獲取硬盤ID的方法

如果你想在Windows電腦上獲取硬盤的ID&#xff0c;可以使用DiskPart命令。以下是具體步驟&#xff1a; 打開命令提示符 按下Win鍵R&#xff0c;輸入cmd&#xff0c;然后回車&#xff0c;即可打開命令提示符。 輸入diskpart并回車 在命令提示符中輸入diskpart&#xff0c;然后…

WordPress 注冊/重置密碼/更改密碼鉤子

wordpress在提供郵件提醒的地方都留了hook&#xff0c;方便讓開發者自定義。最新在添加第三方登錄時遇到虛擬郵箱發信問題&#xff0c;為了防止給指定郵件地址后綴發信&#xff0c;可以利用如下wordpress提供的鉤子來實現。 //https://www.wwttl.com/101.html //禁止用戶注冊時…

用23種設計模式打造一個cocos creator的游戲框架----(十)迭代器模式

1、模式標準 模式名稱&#xff1a;迭代器模式 模式分類&#xff1a;行為型 模式意圖&#xff1a;提供一種方法順序訪問一個聚合對象中的各個元素&#xff0c;且不需要暴露該對象的內部表示. 結構圖&#xff1a; ? 適用于&#xff1a; 1、當你需要遍歷一個復雜的數據結構…

promethesu告警規則配置,alertmanager通過webhook通知

文章目錄 前言一、promethesu告警二、告警配置編寫rule文件prometheus配置prometheus產生告警 三、告警通知prometheus 配置 alertmanageralertmanager 配置 webhook通知編寫接口接收 webhook 總結 前言 如果沒有學習過prometheus的基礎和監控的同學&#xff0c;可以先過一遍這…

融合科技,升級醫療體驗——醫院陪診服務的技術創新

隨著科技的迅猛發展&#xff0c;醫療服務領域也在積極借助技術手段提升患者體驗。本文將探討如何利用先進的技術代碼&#xff0c;將醫院陪診服務推向新的高度。 1. 醫療預約系統的實現 # 通過Python代碼實現醫療預約系統 class MedicalAppointment:def __init__(self, patie…

【Python】Numpy庫近50個常用函數詳解和示例,可作為工具手冊使用

本文以yolo系列代碼為基礎&#xff0c;在其中查找用到的numpy函數&#xff0c;包含近50個函數&#xff0c;本文花費多天&#xff0c;三萬多字&#xff0c;通過豐富的函數原理和示例對這些函數進行詳解。以幫助大家理解和使用。 目錄 np.array()運行示例 np.asarray()函數解析運…

unity 2d 入門 飛翔小鳥 場景延續(八)

1、新建c#腳本如下 代碼&#xff0c;在前方生成生成自身圖片并3s后銷毀自身&#xff0c;在碰撞物體后小鳥死亡后不刪除自身 using System.Collections; using System.Collections.Generic; using UnityEngine;public class CopyScene : MonoBehaviour { //要復制的對象public…

Amazon CodeWhisperer 提供新的人工智能驅動型代碼修復、IaC 支持以及與 Visual Studio 的集成...

Amazon CodeWhisperer 的人工智能&#xff08;AI&#xff09;驅動型代碼修復和基礎設施即代碼&#xff08;IaC&#xff09;支持已正式推出。Amazon CodeWhisperer 是一款用于 IDE 和命令行的人工智能驅動型生產力工具&#xff0c;現已在 Visual Studio 中推出&#xff0c;提供預…

uniapp封裝websocket文件(app、h5兼容)

適合場景&#xff1a;只需要發送一次數據&#xff0c;服務器可以實時返回數據進行渲染。 socket文件 let isSocketClose false; // 是否關閉socket let reconnectCount 5; // 重連次數 // let heartbeatInterval ""; // 心跳定時器 let socketTask null; // web…

uniapp實戰 —— 開發微信小程序的調試技巧

手機真機調試微信小程序 開發版和體驗版的小程序&#xff0c;域名沒有備案時想調試接口訪問效果&#xff0c;可以按下述方式操作&#xff1a; 在手機上點右上方三個點&#xff0c;點擊“開發調試”&#xff0c;開啟調試模式&#xff0c;即可真機訪問接口&#xff08;跳過域名校…

《C++新經典設計模式》之第21章 解釋器模式

《C新經典設計模式》之第21章 解釋器模式 解釋器模式.cpp 解釋器模式.cpp #include <iostream> #include <map> #include <stack> #include <vector> #include <cstring> #include <memory> #include <set> #include <sstream&g…

【Vue3從入門到項目實現】RuoYi-Vue3若依框架前端學習——動態路由與菜單欄

菜單欄 若依框架的側邊欄組件通常由菜單項和子菜單組成。 登錄后&#xff0c;會獲取用戶擁有的路由菜單 {"msg": "操作成功","code": 200,"data": [{"name": "System","path": "/system",…

第一百九十六回 通過藍牙發送數據的細節

文章目錄 1. 概念介紹2. 實現方法3. 代碼與效果3.1 示例代碼3.2 運行效果4. 經驗總結我們在上一章回中介紹了"分享三個使用TextField的細節"沉浸式狀態樣相關的內容,本章回中將介紹SliverList組件.閑話休提,讓我們一起Talk Flutter吧。 1. 概念介紹 通過藍牙設備…

[原創]C++98升級到C++20的復習旅途-個人感覺std::string_literals這個東西實現的不太人性化.

[簡介] 常用網名: 豬頭三 出生日期: 1981.XX.XX QQ聯系: 643439947 個人網站: 80x86匯編小站 https://www.x86asm.org 編程生涯: 2001年~至今[共22年] 職業生涯: 20年 開發語言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 開發工具: Visual Studio、D…

git操作:使用vscode集成

git操作方式 其實git操作一般有三種方式 分別是終端命令行,開發工具集成,專業的git可視化工具 我前面幾章說的都是git的命令行操作,今天這篇文章主要是針對開發工具vscode集成git操作進行演示 說明一下,這里之所以選擇vscode,是因為本人用的就是vscode,每個開發工具基本都有…

最新PyTorch機器學習與深度學習實踐技術應用

近年來&#xff0c;隨著AlphaGo、無人駕駛汽車、醫學影像智慧輔助診療、ImageNet競賽等熱點事件的發生&#xff0c;人工智能迎來了新一輪的發展浪潮。尤其是深度學習技術&#xff0c;在許多行業都取得了顛覆性的成果。另外&#xff0c;近年來&#xff0c;Pytorch深度學習框架受…

mysql怎么優化查詢?

從多個維度優化&#xff0c;這里的優化維度有四個&#xff1a;硬件配置、參數配置、表結構設計和SQL語句及索引。 其中 SQL 語句相關的優化手段是最為重要的。 一、硬件配置 硬件方面的優化可以有 對磁盤進行擴容、將機械硬盤換為SSD&#xff0c;或是把CPU的核數往上提升一些…