当前位置: 首页 > news >正文

策略模式在工作中的运用

前言

在不同的场景下,执行不同的业务逻辑,在日常工作中是很寻常的事情。比如,订阅系统。在收到阿里云的回调事件、与收到AWS的回调事件,无论是收到的参数,还是执行的逻辑都可能是不同的。为了避免,每次新增一种场景,就要改变原有的代码结构,比如,改变原有逻辑,添加 if-else结构,一种可行的方案是,使用策略模式。

策略模式

贴个链接
简单来说,就是根据请求方的类型,执行特定的业务逻辑。

问题点

网络上大部分实现策略模式的代码,很多在将具体的策略注入到Map中时,是以硬编码的方式实现的,比如掘金上的这篇文章:如何优雅的将设计模式运用到实际项目中去?

在工作中借鉴,使用截图
这种方案,虽然可以实现策略模式,但是每次新增策略都要修改这个集合。期望的方案是,新增的策略,自动注入到map中,而不必手动添加。
在这里插入图片描述

为了解决新增策略时,要修改map的情况,调研之后,发现有两种方案:

  1. 美团文章推介的 基于单例的方式,每次启动时,自动将策略注入到map中。
  2. 掘金上另一种方案:基于注解+反射的方式,动态将策略加载到map中。

相比,美团的方案更加优秀,代码改动少,且性能高。不过,本次以方案2为例说明。

代码实现

业务场景

需要提供给外部云厂商回调API,当云服务发生告警时,调用此API,将告警事情同步到服务使用方。
考虑点:

  1. 因为每家厂商的回调参数各有不同,此时,需要定义一个回调对象基类,每个云厂商对应的回调对象继承这个基类,并实现添加其特定的属性。
  2. 因为API是放开到公网上的,因此,为了避免被攻击,除了从集团域名出去外,还对IP进行了频控,比如,调用次数100次/秒。

代码结构

在这里插入图片描述

具体代码

定义实体类

基类

import lombok.Data;/*** @author wangbin16* @date 2024/1/18 15:33*/
@Data
public class CloudAlertBase {/*** name = "alertType", value = "告警类型"*/private Integer alertType;/*** 业务*/private Integer business;
}

阿里云

import lombok.Data;/*** 阿里云监控告警* @author wangbin16* @date 2024/1/18 15:35*/
@Data
public class AliyunCloudAlertAo extends CloudAlertBase {private static final long serialVersionUID = 1L;/*** name = "alertName", value = "报警名称"*/private String alertName;/*** name = "alertState", value = "报警状态"*/private String alertState;/*** name = "curValue", value = "报警发生或恢复时监控项的当前值"*/private String curValue;/*** name = "dimensions", value = "发生报警的对象"*/private String dimensions;/*** name = "expression", value = "报警规则的表达式"*/private String expression;

策略模式

策略基类

/*** @author wangbin16* @date 2024/1/18 15:41*/
public interface CloudAlertStrategy {/*** 处理云监控告警* @param param*/void handleCloudAlert(CloudAlertBase param);
}

阿里云策略

@Slf4j
@Service
@CloudAlertAnnotation(alertType = CloudAlertTypeEnum.ALIYUN)
public class AliyunCloudAlertStrategy implements CloudAlertStrategy {@Overridepublic void handleCloudAlert(CloudAlertBase param) {// TODO 处理阿里云监控告警// 暂时先发送给我 @wangbin16SendMsgUtils sendMsgUtils = new SendMsgUtils();sendMsgUtils.sendP2pPopoMsg(JSON.toJSONString(param), "wangbin16@xxx", "【阿里云监控告警】");}
}
策略注册
import org.reflections.Reflections;import java.util.HashMap;
import java.util.Map;
import java.util.Set;/*** @author wangbin16* @date 2024/1/18 15:50*/
public class AnnotationCloudAlertStrategyFactory {/*** 存储策略*/static Map<Integer, CloudAlertStrategy> strategyMap = new HashMap<>();static {registerStrategy();}/*** 自动注册策略*/private static void registerStrategy() {// 通过反射获取所有的策略类Reflections reflections = new Reflections(CloudAlertStrategy.class.getPackage().getName());Set<Class<? extends CloudAlertStrategy>> cloudStrategyClassSet = reflections.getSubTypesOf(CloudAlertStrategy.class);if (cloudStrategyClassSet != null) {for (Class<?> clazz : cloudStrategyClassSet) {// 找到类型注解,自动完成策略注册if (clazz.isAnnotationPresent(CloudAlertAnnotation.class)) {CloudAlertAnnotation alertTypeAnnotation = clazz.getAnnotation(CloudAlertAnnotation.class);CloudAlertTypeEnum chargeType = alertTypeAnnotation.alertType();try {strategyMap.put(chargeType.getCode(), (CloudAlertStrategy) clazz.newInstance());} catch (InstantiationException | IllegalAccessException e) {e.getStackTrace();}}}}}/*** 提供注册策略接口,外部只需要调用此接口接口新增策略* 策略定义时,即注入,这是口子*/public static void registerChargeStrategy(CloudAlertTypeEnum alertType, CloudAlertStrategy strategy) {strategyMap.put(alertType.getCode(), strategy);}
}

策略选择器

@Service
@Slf4j
public class CloudAlertStrategySelector {public CloudAlertStrategy selector(Integer alertType) {if (alertType == null) {return null;}return AnnotationCloudAlertStrategyFactory.strategyMap.get(alertType);}
}

服务调用

@Slf4j
@Service("cloudMonitorService")
public class CloudMonitorService {@Autowiredprivate CloudAlertStrategySelector cloudAlertStrategySelector;public void handleCloudMonitor(CloudAlertBase param) {logger.info("handleCloudMonitor param:{}", JSON.toJSONString(param));CloudAlertStrategy selector = cloudAlertStrategySelector.selector(param.getAlertType());if (selector != null) {selector.handleCloudAlert(param);} else {logger.error("外部云告警异常调用, param:{}", JSON.toJSONString(param));}}
}

测试

调用指定的接口,执行指定的逻辑
在这里插入图片描述

相关文章:

策略模式在工作中的运用

前言 在不同的场景下&#xff0c;执行不同的业务逻辑&#xff0c;在日常工作中是很寻常的事情。比如&#xff0c;订阅系统。在收到阿里云的回调事件、与收到AWS的回调事件&#xff0c;无论是收到的参数&#xff0c;还是执行的逻辑都可能是不同的。为了避免&#xff0c;每次新增…...

【go】依赖倒置demo

文章目录 前言1 项目目录结构&#xff1a;2 初始化函数3 router4 api5 service6 dao7 Reference 前言 为降低代码耦合性&#xff0c;采用依赖注入的设计模式。原始请求路径&#xff1a;router -> api -> service -> dao。请求的为实际方法&#xff0c;具有层层依赖的…...

C++ //练习 2.5 指出下述字面值的数据类型并说明每一组内几种字面值的区别:

C Primer&#xff08;第5版&#xff09; 练习 2.5 练习 2.5 指出下述字面值的数据类型并说明每一组内几种字面值的区别&#xff1a; ( a ) ‘a’, L’a’, “a”, L"a" ( b ) 10, 10u, 10L, 10uL, 012, 0xC ( c ) 3.14, 3.14f, 3.14L ( d ) 10, 10u, 10., 10e-2…...

必示科技助力中国联通智网创新中心通过智能化运维(AIOps)通用能力成熟度3级评估

2023年12月15日&#xff0c;中国信息通信研究院隆重公布了智能化运维AIOps系列标准最新批次评估结果。 必示科技与中国联通智网创新中心合作的“智能IT故障监控定位分析能力建设项目”通过了中国信息通信研究院开展的《智能化运维能力成熟度系列标准 第1部分&#xff1a;通用能…...

python数字图像处理基础(九)——特征匹配

目录 蛮力匹配&#xff08;ORB匹配&#xff09;RANSAC算法全景图像拼接 蛮力匹配&#xff08;ORB匹配&#xff09; Brute-Force匹配非常简单&#xff0c;首先在第一幅图像中选取一个关键点然后依次与第二幅图像的每个关键点进行&#xff08;描述符&#xff09;距离测试&#x…...

k8s的对外服务ingress

1、service的作用体现在两个方面 &#xff08;1&#xff09;集群内部&#xff1a;不断跟踪pod的变化&#xff0c;更新deployment中的pod对象&#xff0c;基于pod的ip地址不断变化的一种服务发现机制 &#xff08;2&#xff09;集群外部&#xff1a;类似于负载均衡器&#xff…...

[足式机器人]Part2 Dr. CAN学习笔记- Kalman Filter卡尔曼滤波器Ch05-3+4

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记 - Kalman Filter卡尔曼滤波器 Ch05-34 3. Step by step : Deriation of Kalmen Gain 卡尔曼增益/因数 详细推导4. Priori/Posterrori error Covariance Martix 误差协方差矩阵 3. Step by step :…...

关于前端面试中forEach方法的灵魂7问?

目录 前言 一、forEach方法支持处理异步函数吗&#xff1f; 二、forEach方法在循环过程中能中断吗&#xff1f; 三、forEach 在删除自己的元素后能重置索引吗&#xff1f; 四、forEach 的性能相比for循环哪个好&#xff1f; 五、使用 forEach 会不会改变原来的数组&#…...

AI小程序添加深度合成类目解决办法

基于文言一心和gpt等大模型做了一个ai助理小程序&#xff0c;在提交“一点AI助理”小程序时&#xff0c;审核如下&#xff1a; 失败原因1 审核失败原因 你好&#xff0c;你的小程序涉及提供提供文本深度合成技术 (如: AI问答) 等相关服务&#xff0c;请补充选择&#xff1a;深度…...

C/C++ BM6判断链表中是否有环

文章目录 前言题目解决方案一1.1 思路阐述1.2 源码 解决方案二2.1 思路阐述2.2 源码 总结 前言 做了一堆单链表单指针的题目&#xff0c;这次是个双指针题&#xff0c;这里双指针的作用非常明显。 题目 判断给定的链表中是否有环。如果有环则返回true&#xff0c;否则返回fal…...

【Java 设计模式】结构型之适配器模式

文章目录 1. 定义2. 应用场景3. 代码实现结语 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;用于将一个类的接口转换成客户端期望的另一个接口。这种模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。在本文中&#xff0c;我…...

使用函数计算,数禾如何实现高效的数据处理?

作者&#xff1a;邱鑫鑫&#xff0c;王彬&#xff0c;牟柏旭 公司背景和业务 数禾科技以大数据和技术为驱动&#xff0c;为金融机构提供高效的智能零售金融解决方案&#xff0c;服务银行、信托、消费金融公司、保险、小贷公司等持牌金融机构&#xff0c;业务涵盖消费信贷、小…...

卷积和滤波对图像操作的区别

目录 问题引入 解释 卷积 滤波 问题引入 卷积和滤波是很相似的&#xff0c;都是利用了卷积核进行操作 那么他们之间有什么区别呢&#xff1f; 卷积&#xff1a;会影响原图大小 滤波&#xff1a;不会影响原图大小 解释 卷积 我们用这样一段代码来看 import torch.nn as …...

李沐深度学习-线性回归从零开始

# 核心Tensor&#xff0c;autograd import torch from IPython import display import numpy as np import random from matplotlib import pyplot as pltimport syssys.path.append(路径) from d2lzh_pytorch import * backward()函数:一次小批量执行完在进行反向传播 线性回归…...

CentOS 8.5 安装图解

特特特别的说明 CentOS发行版已经不再适合应用于生产环境&#xff0c;客观条件不得不用的话&#xff0c;优选7.9版本&#xff0c;8.5版本次之&#xff0c;最次6.10版本&#xff08;比如说Oracle 11GR2就建议在6版本上部署&#xff09;&#xff01; 引导和开始安装 选择倒计时结…...

好用的流程图工具

分享工作中常用的装逼工具 目前市面上的流程图或者思维导图工具挺多的&#xff0c;但是有的会限制使用数量或者收费&#xff0c;典型的有processon、Xmind&#xff0c;推荐今天Mermaid(官网)。 快速上手 中文教程&#xff1a;Mermaid 初学者用户指南 | Mermaid 中文网。我们选择…...

数据结构:链式栈

stack.h /* * 文件名称&#xff1a;stack.h * 创 建 者&#xff1a;cxy * 创建日期&#xff1a;2024年01月18日 * 描 述&#xff1a; */ #ifndef _STACK_H #define _STACK_H#include <stdio.h> #include <stdlib.h>typedef struct stack{int data…...

openssl3.2 - 官方demo学习 - mac - gmac.c

文章目录 openssl3.2 - 官方demo学习 - mac - gmac.c概述笔记END openssl3.2 - 官方demo学习 - mac - gmac.c 概述 使用GMAC算法, 设置参数(指定加密算法 e.g. AES-128-GCM, 设置iv) 用key执行初始化, 然后对明文生成MAC数据 官方注释给出建议, key, iv最好不要硬编码出现在程…...

HugggingFace 推理 API、推理端点和推理空间相关模型部署和使用以及介绍

HugggingFace 推理 API、推理端点和推理空间相关模型部署和使用以及介绍。 Hugging Face是一家开源模型库公司。 2023年5月10日&#xff0c;Hugging Face宣布C轮1亿美元融资&#xff0c;由Lux Capital领投&#xff0c;红杉资本、Coatue、Betaworks、NBA球星Kevin Durant等跟投…...

python的tabulate包在命令行下输出表格不对齐

用tabulate可以在命令行下输出表格。 from tabulate import tabulate# 定义表头 headers [列1, 列2, 列3]# 每行的内容 rows [] rows.append((张三,数学,英语)) rows.append((李四,信息科技,数学))# 使用 tabulate 函数生成表格 output tabulate(rows, headersheaders, tab…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...

解析“道作为序位生成器”的核心原理

解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制&#xff0c;重点解析"道作为序位生成器"的核心原理与实现框架&#xff1a; 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...