【抽象策略模式】实践

前言

刚果商城,用户登录 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.mzph.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 信号,我们用…

用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实战 —— 开发微信小程序的调试技巧

手机真机调试微信小程序 开发版和体验版的小程序&#xff0c;域名没有备案时想调试接口访问效果&#xff0c;可以按下述方式操作&#xff1a; 在手机上点右上方三个点&#xff0c;点击“开发调试”&#xff0c;开启调试模式&#xff0c;即可真机访问接口&#xff08;跳过域名校…

【Vue3从入门到项目实现】RuoYi-Vue3若依框架前端学习——动态路由与菜单栏

菜单栏 若依框架的侧边栏组件通常由菜单项和子菜单组成。 登录后&#xff0c;会获取用户拥有的路由菜单 {"msg": "操作成功","code": 200,"data": [{"name": "System","path": "/system",…

git操作:使用vscode集成

git操作方式 其实git操作一般有三种方式 分别是终端命令行,开发工具集成,专业的git可视化工具 我前面几章说的都是git的命令行操作,今天这篇文章主要是针对开发工具vscode集成git操作进行演示 说明一下,这里之所以选择vscode,是因为本人用的就是vscode,每个开发工具基本都有…

spark链接hive时踩的坑

使用spark操作hive&#xff0c;使用metastore连接hive&#xff0c;获取hive的数据库时&#xff0c;当我们在spark中创建数据库的时候&#xff0c;创建成功。 同时hive中也可以看到这个数据库&#xff0c;建表插入数据也没有问题&#xff0c;但是当我们去查询数据库中的数据时&a…

IDEA 出现问题:Idea-操作多次commit,如何合并为一个并push解决方案

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

Python---继承

1、什么是继承 我们接下来来聊聊Python代码中的“继承”&#xff1a;类是用来描述现实世界中同一组事务的共有特性的抽象模型&#xff0c;但是类也有上下级和范围之分&#xff0c;比如&#xff1a;生物 > 动物 > 哺乳动物 > 灵长型动物 > 人类 > 黄种人 从哲学…

通过rc.local开机自启执行nohup命令运行Flask,nohup.out中没有Flask请求响应日志

需求 通过修改/etc/rc.d/rc.local&#xff0c;实现开机自启Flask服务&#xff0c;CentOS 7.9。rc.local参考链接1&#xff0c;参考链接2。 问题 在/etc/rc.d/rc.local中添加 /home/python/face_jiance/kaijiziqi.sh 在/home/python/face_jiance/kaijiziqi.sh中写 nohup /…

数据可视化软件的兴起:背后的驱动力

在当今信息时代&#xff0c;数据变得比以往任何时候都更为重要。数据可视化软件的广泛应用成为了一种趋势。那么&#xff0c;为什么越来越多的人选择使用数据可视化软件呢&#xff1f;今天我就以自己的工作经验为基础&#xff0c;进行简单的分析。 数据可视化软件能将枯燥的数…

react-lazyload 的介绍、安装、使用。

目录 基本介绍 安装 使用 基本使用 详细属性 基本介绍 react-lazyload 是一个 React 组件&#xff0c;用于延迟加载&#xff08;懒加载&#xff09;页面上的图片或其他资源。懒加载是一种优化手段&#xff0c;它允许页面在初次加载时只加载可视区域内的内容&#xff0c;…

vue3移动端脚手架(纯净,集成丰富)

概述 一个纯净的移动端框架 &#xff0c;用到了 Vue3 vuex Vite3 Vant3 sass eslint stylelint htmlhint husky commitlint axios axios-adapter VConsole 自定义全局 loading &#xff0c;自定义函数式 dialog &#xff08;api模仿微信小程序&#xff09;&#x…

增强现实中的真实人/机/环与虚拟人/机/环

在增强现实中&#xff0c;真实人与虚拟人、真实机器与虚拟机器、真实环境与虚拟环境之间有着密切的关系。增强现实技术通过将真实与虚拟相结合&#xff0c;打破了传统的现实世界与虚拟世界的界限&#xff0c;创造出了一种新的体验方式。真实人、真实机器和真实环境与其对应的虚…