策略模式在工作中的运用

news2024/12/25 9:22:15

前言

在不同的场景下,执行不同的业务逻辑,在日常工作中是很寻常的事情。比如,订阅系统。在收到阿里云的回调事件、与收到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 {
    @Override
    public void handleCloudAlert(CloudAlertBase param) {
        // TODO 处理阿里云监控告警

        // 暂时先发送给我 @wangbin16
        SendMsgUtils 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 {
    @Autowired
    private 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));
        }
    }
}

测试

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1394196.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

老师布置作业的技巧有哪些

布置作业可不只是简单地给学生分配任务&#xff0c;而是需要运用一些技巧&#xff0c;以达到更好的教学效果。那么&#xff0c;老师应该如何布置作业呢&#xff1f; 一、作业要有针对性 布置作业时&#xff0c;老师应该根据学生的实际情况和课程要求&#xff0c;有针对性地设…

数字创意市场:Web3时代创作者的新机遇

随着Web3时代的崭露头角&#xff0c;数字创意市场正迎来全新的变革和机遇。在这个数字化的时代&#xff0c;创作者们将面对更加开放、去中心化的创作和交易环境。本文将深入探讨Web3时代数字创意市场为创作者带来的新机遇&#xff0c;以及这个时代为创意产业带来的变革。 创作者…

无心剑七绝《忆彭德怀》

七绝忆彭德怀 彭公铁骨傲苍松 德布黎民逆赤龙 怀义光华传百代 真金火炼自从容 2024年1月16日 平水韵二冬平韵 这首七绝以“忆彭德怀”为题&#xff0c;通过四句二十八字的凝练表达&#xff0c;深情缅怀了彭德怀元帅的高尚品质和坚韧精神。作者无心剑运用古典诗词的形式&#xf…

区域入侵/区域人数统计AI边缘计算智能分析网关V4如何修改IP地址?

智能分析网关V4是TSINGSEE青犀推出的一款AI边缘计算智能硬件&#xff0c;硬件采用BM1684芯片&#xff0c;集成高性能8核ARM A53&#xff0c;主频高达2.3GHz&#xff0c;INT8峰值算力高达17.6Tops&#xff0c;FB32高精度算力达到2.2T&#xff0c;硬件内置了近40种AI算法模型&…

IaC基础设施即代码:Terraform使用本地编译(In-house)的Providers

目录 一、实验 1.环境 2.初始化一个项目 3.Terraform使用本地编译&#xff08;In-house&#xff09;的Providers 二、问题 1.Terraform Provider有哪些全网标识符 2.本地安装Terraform Provider有哪些方法 一、实验 1.环境 &#xff08;1&#xff09;主机 表1-1 主机…

Spring | Spring中的Bean--上

目录: Spring中的Bean:1.Bean的配置2.Bean的实例化2.1 构造器实例化 3.Bean的作用域3.1 作用域的种类3.2 singleton作用域3.3 prototype 作用域 Spring中的Bean: 1.Bean的配置 Spring可以被看作是个一个大型工厂&#xff0c; 这个工厂的作用就是生产和管理Sping容器中的Bean。…

QtCreator12无法识别Qt5.15.2的安卓SDK与NDK配置解决

解决方法: 设置JDK为JDK11 使用Android Studio下载 Android SDK Command-line Tools 10.0 打开Android SDK Location : 双击打开cmdline-tools 复制10.0中所有东西到latest中 点击Manage Kits并选择Devices 然后点击Android会弹出下图窗口,并自动更 安装完成 成功识别

Jupyter Notebook五分钟基础速通

1 作用 常用于数据分析 2 安装 2.1 Anaconda 通过直接安装Anaconda&#xff0c;会自动安装Jupyter Notebook 2.2 命令行安装 ① 3.x版本 pip3 install --upgrade pip pip3 install jupyter ② 2.x版本 pip install --upgrade pip pip install jupyter 3 启动 cmd窗口下…

Spring+SpringMVC+Mybatis进行项目的整合

Spring SpringMVCM Mybatis 整合 一、 通过idea创建maven工程 二、 引入依赖项以及导入mybatis逆向工程的插件 将如下的文件替换所在工程的pom文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4…

Java_二叉树详解

前言 程序员优劣之间最明显的就是数据结构和算法的掌握程度,二叉树作为数据结构中不可缺少的一员,可见其重要程度.我们一起来简单地学习二叉树吧~ 树型结构 在我们学习二叉树前先了解一下树型结构(二叉树是树型结构中的一种) 树是一种非线性的数据结构,它是有n (n>0) 个…

css-动画效果学习示例

阴影 x-轴 y-轴 模糊度 颜色 (正负值可以表示角度问题) 可以加多个阴影 内置阴影 transition 可以添加动画延迟效果 向z轴缩进&#xff0c;开启透视respective 触发旋转效果 学习来源 &#xff1a;动画属性_哔哩哔哩_bilibili

JavaScript 学习笔记(WEB APIs Day1)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. JavaScript 学习笔记&#xff08;Day1&#xff09; 2. JavaSc…

【Proteus仿真】【STM32单片机】甲醛浓度检测报警器

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用蜂鸣器LED模块、LCD1602显示模块、按键、MS1100甲醛传感器模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示甲醛气体浓度检测…

物联网孢子捕捉分析仪在农田起到什么作用

TH-BZ03随着科技的飞速发展&#xff0c;物联网技术在农业领域的应用越来越广泛。其中&#xff0c;物联网孢子捕捉分析仪作为一种先进的设备&#xff0c;在农田中发挥着不可或缺的作用。本文将详细介绍物联网孢子捕捉分析仪在农田中的作用。 一、实时监测与预警 物联网孢子捕捉分…

【Docker】使用Docker安装Nginx及部署前后端分离项目应用

一、Nginx介绍 Nginx是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。它是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发的&#xff0c;公开版本1.19.6发布于2020年12月15日。其将源代码以类BSD许可证的形式发布&#xff0c;因它…

项目经理进阶之路:如何应对不同阶段的挑战?

最近看到一个帖子&#xff0c;有网友提问&#xff0c;“项目经理的职业发展会经历哪几个阶段&#xff1f;不同阶段需要关注什么&#xff1f;又分别会遇到哪些挑战&#xff1f;“这个帖子引发了广大项目经理们的热议&#xff0c;大家纷纷吐槽&#xff0c;自己遇到了职业瓶颈、询…

Qt SDL2播放Wav音频

这里介绍两种方法来实现Qt播放Wav音频数据。 方法一&#xff1a;使用QAudioOutput pro文件中加入multimedia模块。 #include <QApplication> #include <QFile> #include <QAudioFormat> #include <QAudioOutput>int main(int argc, char *argv[]) {…

RK3566 linux修改CMA size

1、进入内核配置界面 执行命令&#xff1a; cd kernel make ARCHarm64 menuconfig 2、搜索CONFIG_CMA_SIZE_MBYTES 在配置界面输入/搜索CONFIG_CMA_SIZE_MBYTES&#xff0c;结果如下&#xff1a; 根据提示进入以下界面&#xff1a; 修改Size in Mega Bytes的值。

【时间复杂度】时间复杂度优化法则简讲

一、引言 时间复杂度是衡量算法运行效率的一项重要指标&#xff0c;它描述了随着输入规模的增加&#xff0c;算法的执行时间如何增长。在算法设计与分析中&#xff0c;我们经常面临着优化时间复杂度的任务&#xff0c;以便提高程序的性能。本博客将深入探讨时间复杂度的优化法…

UJA1169A恢复出厂设置(Restoring factory preset values)

UJA1169A是一款CAN芯片&#xff0c;同时又带有硬件看门狗的功能。出厂默认是Forced Normal模式&#xff0c;此时看门狗是禁用的。CAN通信的正常功能是在Forced Normal/Normal模式下才好用的&#xff0c;Normal模式下需要配置。包含位FNMC&#xff08;地址74h&#xff09;的寄存…