重构实例-消息发送-使用策略进行重构-Map方式-6

进程内的消息通知 背景 我们团队,由于原python项目由于可维护性的降低、开发成本和周期的增长、扩展性差,已经逐渐适应不了公司业务的发展,面临不得不重构项目。该项目主要使用django+celery单体服务、29万行pyton代码、约1500个接口,包含仓库中的商品信息、仓库信息、库存管理、库内流程、出库流程、入库流程等各种业务。在业务发展初期,为了快速的完成业务迭代,模块间的通信方式都是直接函数调用,这种方式简单、直观。但随着业务的发展,直接调用的方式使得整个项目耦合严重、理解难度增加,进而使得开发效率骤减、bug急剧增 阅读详情

6 重构实例-消息发送-使用策略进行重构-Map方式

由于这是一个长文,分成了好几章来介绍如何重构。

  1. 原始代码及准备
  2. 职责独立
  3. 去除static关键字
  4. 接口添加转换方法
  5. 方法合并
  6. 使用策略进行重构-Map方式
  7. 使用策略进行重构-枚举方式

6.1 问题分析

经过前两轮的重构之后,已经提取了抽象接口,并将其static去掉。还为消息发送接口添加了转换方法,并对代码进行了方法的合并操作。

经过这几轮的修改,代码已经看起来整洁、清晰了许多。但是还存在一个问题,那就是每当要添加一个新的渠道的时候,就得改动MessageSender类,在switch/case语句中添加一个判断,这样子确实可以实现功能,那有没有可能在不改动这个代码,或者改动很少的代码就能添加呢?这里可能会有好多人就不乐意了。

可能会说,这里我已经通过switch/case判断了,直接添加一个不是也挺容易的么?为什么还要求在不改动代码或者更少改动代码呢?这不是强人所难么!这个确实没有问题,如果是一般的重构,到这里确实可以算做结束了,那为什么还要追求少改代码或者不改代码呢?这个其实还是人的问题,还是在原功能上增加新功能为例吧,如果采用直接修改代码的方式,那必然带来原先的有些功能可能会出现
问题的风险;如果采用是直接在一个新的代码中完成相关功能,然后将新功能 注入到原先的代码中,这样是不是出现问题的风险被大大降低。

出于这样的一个考量,如果能做到不改或者少改代码,那对于新功能的扩展,带来了更大的福音。
来打开下上次重构完成的代码:

public class MessageSender {

  public void sendMessage(String msgType, MessageData notify) {
    MessageTypeEnum typeEnum = MessageTypeEnum.getEnumType(msgType);
    switch (typeEnum) {
        // 短信发送
      case SMS:
        MessageSenderInf smsSender = new SmsSender();
        smsSender.sender(smsSender.parse(notify));
        break;
        // email的发送
      case EMAIL:
        MessageSenderInf emailSender = new EmailSender();
        emailSender.sender(emailSender.parse(notify));
        break;
        // 微信的发送
      case WECHAT:
        MessageSenderInf weChatSender = new WeChatSender();
        weChatSender.sender(weChatSender.parse(notify));
        break;
        // 钉钉的消息发送
      case DINGDING:
        MessageSenderInf dingDingSender = new DingDingSender();
        dingDingSender.sender(dingDingSender.parse(notify));
        break;
        // 企业钉钉的消息发送
      case WORKWECHAT:
        MessageSenderInf workWeChatSender = new WorkWeChatSender();
        workWeChatSender.sender(workWeChatSender.parse(notify));
        break;
        // 其他不做处理
      case OTHER:
        break;
      default:
        break;
    }
  }
}

来看看有没有可能实现呢!我觉得这个得从switch/case的本质出发,找到了问题的本质,才能有其他的解,那swatch/case本质是什么呢?脑补下,
想想平时用switch/case是做什么呢?我觉得switch/case从已知的条件中,匹配一个条件,然后执行这个条件成立的逻辑。想想case SMS:,那就是当
消息类型为sms时,执行sms的发送。其他的也可类比,那既然是匹配条件,也可以用其他的匹配手段啊!比如使用map进行key的匹配,或者集合,
顺序遍历匹配,是的就是这样子。
既然如此,来看看代码实现,如何使用集合对此代码过时行改造。我分为两种方案,1,使用map的式试,2 使用数组的方式。当然还有其他可扩展方式,
其他就与此类似可自行实现。

6.2 使用map方案来重构。

6.2.1 重构步骤

  1. 检查单元测试。
  2. 对代码进行改造。
  3. 运行单元测试,以验证修改的正确性。

6.2.2 检查单元测试

由于在之前做发送消息相关验证时,单元测试的相当相关功能已经覆盖,可直接使用,此步骤可以跳过。

6.2.3 对代码进行改造。

public class MessageSender {

  /** 按类型存储发送相关实例 */
  private static final Map<MessageTypeEnum, MessageSenderInf> MSG_INSTANCE = new HashMap<>(5);

  static {
    // 1,SMS发送
    MSG_INSTANCE.put(MessageTypeEnum.SMS, new SmsSender());
    // 2. EMAIL发送
    MSG_INSTANCE.put(MessageTypeEnum.EMAIL, new EmailSender());
    // 3. dingding发送
    MSG_INSTANCE.put(MessageTypeEnum.DINGDING, new DingDingSender());
    // 4. wechat发送
    MSG_INSTANCE.put(MessageTypeEnum.WECHAT, new WeChatSender());
    // 5. 工作微信
    MSG_INSTANCE.put(MessageTypeEnum.WORKWECHAT, new WorkWeChatSender());
  }

  /**
   * 消息发送
   *
   * @param msgType 消息类型
   * @param notify 消息信息
   */
  public void sendMessage(String msgType, MessageData notify) {
    MessageTypeEnum typeEnum = MessageTypeEnum.getEnumType(msgType);
    MessageSenderInf msgSender = MSG_INSTANCE.get(typeEnum);
    if (null == msgSender) {
      return;
    }

    // 消息的发送操作
    msgSender.sender(msgSender.parse(notify));
  }
}

这里是直接硬编码在代码中的,这种方式在一般场景下对于更少改动代码,还是有较好的帮助了,它至少脱离了在逻辑中去修改修改。每次需要增加一个发送
类型,直接增加一个相应的实现类,然后注入至这个容器中即可。还有一种更好的,那就是与我们开发常使用的spring框架相结合,使用spring的框架的
依赖注入的特性,帮我们完成对实例的注入。这样真的做理想的程度。也才真的做到了对修改关闭,对扩展开放的一个原则。

6.2.4 运行单元测试。

当代码运行完成之后使用map重构的方案已经结束了

当这个重构完成后,我想你基本能理解策略模式了。这就是一个简单的策略模式的应用,可能好多人都没有想过吧,这就是策略模式,离我们如此之近?

HarmonyOS 6原生重构:从App开发到系统能力编排的范式迁移 HarmonyOS 6并非Android兼容层升级,而是以Stage模型、ArkTS语言和分布式能力为核心的全新操作系统范式。其核心原理在于将应用生命周期、后台调度、安全执行等关键逻辑收归系统管控,强制开发者转向‘能力调用’而非‘代码堆砌’——例如ExtensionAbility替代Service、TEE可信执行环境开箱即用、WantAgent实现跨设备意图调度。这一转变带来显著技术价值:更细粒度的资源控制、更高确定性的安全边界、更轻量的业务逻辑。典型应用场景涵盖政务核验(交管12123)、出行协同(高德融 阅读详情

相关推荐

Linux内存优化:KSM技术原理与实践指南

内存共享是提升虚拟化环境资源利用率的关键技术,其核心原理是通过识别相同内容的内存页进行合并。Linux内核的KSM(Kernel Samepage Merging)机制采用红黑树数据结构管理内存页,通过多级哈希比较算法实现高效合并。该技术能显著降低物理内存消耗,提升CPU缓存命中率,特别适用于运行大量相似虚拟机实例的场景。在容器化和云计算环境中,KSM与NUMA优化、内存气球等技术协同,可实现40%-60%的内存节省。典型应用包括金融云平台的高密度虚拟机部署,以及Kubernetes集群的基础镜像优化。

weixin_28730353的博客 369

Java学习

第1章 计算机基础 1.1 走进0与1的世界 为什么正数不断无符号右移(>>>)的最小值是0;负数不断无符号右移(>>>)的最小值是1 ? 在实际编程中,无符号右移运算一般只用于短整型(32位)和长整型(64位)数上。由于移位运算实际上移动的位数是一个mod32或者mod64的结果(包括有符号位移“>>“ "<<"也是取余运算)。 对于短整型数(32位)来说,移动的位数是一个mod32的结果,即35>>>1与35>>

qq_37586652的博客 1473

手把手教你用UNI-MOL进行分子性质预测:从3D构象到实战结果

本文提供了使用UNI-MOL进行分子性质预测的完整实战指南。通过详细的环境搭建、3D构象生成、模型加载与微调步骤,手把手教你构建端到端的预测流水线。文章重点解析了如何利用UNI-MOL的3D分子表示学习能力,超越传统2D方法,实现对溶解度、活性等性质的更精准预测,并探讨了结果解读与模型分析方法。

weixin_29164091的博客 116

js-设计模式-策略模式

js策略模式

junjiahuang的博客 332

告别硬件!用Wokwi在线模拟ESP32点灯,5分钟搞定开发环境搭建

本文介绍如何使用Wokwi在线模拟器快速搭建ESP32开发环境,5分钟内完成点灯实验。无需硬件即可体验GPIO控制、PWM调光等核心功能,特别适合物联网开发初学者和快速原型验证。Wokwi的零成本、全功能模拟特性让嵌入式开发变得前所未有的简单高效。

weixin_42567497的博客 494

Discrete Optimization (Coursera) 学习笔记 Week 1 introduction (开个帖子)

Week 1 Introduction 这位教授Pascal Van Hentenryck 真的算是优化领域神级别的人物了吧?截一张Google scholar的图大家感受一下… 居然在Coursera上看到了他开的课:Discrete Optimization。试听了几节后,发现讲得很有激情,而且深入浅出。遂决定花暑假跟完这一门课。 这门课每周花两三个小时介绍基础概念,然后得花十几个小时写作业(coding)… 一开始以为Coursera上的课的作业应该不会太难,然后第一次作业(knapsack)我就被

ZJ_11701的博客 656

Java 代码重构 (一)

Java代码重构(一) 项目中代码开发规范要求 对于企业项目来说,开发规范约束是主要的代码规范约束之一,除遵循行业的开发规范外,企业内部也会定义 一套属于自己的代码开发规范,所以任何的开发规范都是以整体统一规范为前提的,不过我们可以自己在开发 的过程中遵循一些基本的开发规范,养成自己的编程风格,形成良好的代码开发习惯。 项目中开发规范约束 1、包的命名应该采用小写英文单词(名词)根据模块进行命名...

欢迎来到我的技术分享博客!这里将带你深入了解AI技术、Java架构设计、系统开发与优化等前沿技术内容。我专注于从实战经验 3029

【SPSS实战】手动实现Quade非参数协方差分析:从数据准备到结果解读

本文详细介绍了在SPSS中手动实现Quade非参数协方差分析的全过程。针对数据不满足正态性和方差齐性假设时,如何通过秩转换、回归调整残差,并最终利用Kruskal-Wallis检验完成组间比较。该方法为处理含协变量的非参数多组比较问题提供了清晰的实战解决方案,并探讨了其与标准Quade检验的异同及适用场景。

weixin_29306317的博客 356

数据数组重构用map()方法和for方法

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。 rewardResolve(rawData, rawProb) { rawData = rawData ? JSON.parse(rawData) : []; rawProb = rawProb ? JSON.parse(rawProb) : []; const result = rawData.map((bigGift, bigGift

chose_DoIt的博客 710

电路板保险丝如何选型

在电路板保险丝选型过程中,需要考虑多个因素以确保其适合特定的电路需求。最后,经过以上程序选定的样品需要在实际的电路中进行测试,以验证所选择的保险丝是否合适。

weixin_57010826的博客 1310

OpenCV计算机视觉实战(11)——边缘检测详解

在本节中,我们系统介绍了三大经典边缘检测算子,包括 Sobel 算子:一阶导数平衡了噪声抑制与边缘提取,结合方向信息可用于纹理分析与车道检测;Laplacian 算子:二阶导数对微小亮度突变尤为敏感,配合零交叉和细化技术,可精确捕捉任意方向的细节边缘;Canny 算法:集成多阶段处理与双阈值策略,通过多尺度融合与自适应阈值优化,达到抗噪与细节兼顾的卓越效果。

qq_30167691的博客 4375

数组map方法及重构

数组map方法及重构 介绍:map方法遍历数组,map返回一个由map中的回调函数return出的元素组成的数组。返回数组的长度与arr相同 重构: function map(arr,fn){ var arr1=[] for(var i=0;i<arr.length;i++){ if(i in arr) arr1[i]=fn(arr[i],i,arr); } return arr1; } ...

weixin_46165733的博客 566

基于深度学习的水果新鲜程度检测系统(UI界面 + YOLOv8/v7/v6/v5代码 + 训练数据集)

本文详细介绍了如何使用YOLO系列模型(YOLOv5、YOLOv6、YOLOv7、YOLOv8)构建水果新鲜度检测系统。通过数据集准备、模型训练、推理过程以及UI界面的实现,我们能够构建一个实时检测水果新鲜度的系统。通过本博客,您可以全面了解如何应用深度学习技术解决实际问题,尤其是在智能监控和食品质量检测领域。

YOLO 815

重构实例-消息发送-使用策略进行重构-枚举方式-7

7. 重构实例-消息发送-使用策略进行重构-枚举方式 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 经过上一次的重构我想你基本理解了使用map的策略模式,我们再来看使用策略模式的另一种实现list 7.1 重构步骤 这个还是规矩 检查单元测试。 使用枚举将类型与实例相绑定。 进行策略的实现。 执行单元测试。 7.2 检查单元测试 这个单元测试没有变化,可跳过 7.

bug_null的博客 209

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

重构实例-消息发送-原始代码及准备-1

1. 重构-策略模式-原始代码及准备 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 1.1 原始代码 这是来自于我所经历的项目中一个消息发送的程序,调用者告诉发送程序:类型、接收者及消息的内容,发送程序会根据发送的类型调用不同的发送程序,将待发送的消息发送出去。 目前已知的发送渠道包括:短信、email、微信、钉钉、企业微信, 由于短信、email、微信、钉钉、企业

bug_null的博客 327

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

重构实例-消息发送-职责独立-2

2. 重构-策略模式-职责独立 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 现在来分析下代码的问题 先从入口MessageSender开始吧,这个类第一眼看上去,觉得很简单吧,就是按类型判断下,执行NotifySendUtils类中 的发送逻辑代码。这样子看这个类没有什么大的问题么,再说NotifySendUtils吧,它封装了各种发送渠道的调用方法,还做成了静态方

bug_null的博客 312

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

重构实例-消息发送-去除static关键字-3

3. 重构实例-消息发送-去除static关键字 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 现在来思考下NotifySendUtils中直接调用发送代码的做法,是否合理呢?或者说在我们原来的代码中,增加了一层调用,有必要吗?我觉得这个问题得分场景 来看,如果是一个大系统中的一部分,NotifySendUtils被几十甚至上百的文件引用,那么这样的改动是相当合理的,

bug_null的博客 262

重构实例-消息发送-添加转换方法-4

4.重构实例-消息发送-添加转换方法 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 经过前两轮的重构之后,已经提取了抽象接口,并将其static去掉。经过这两轮重构后,有没有什么设计是不合理的呢?再次回收代码中: public class MessageSender { public void sendMessage(String msgType, Messag

bug_null的博客 307

重构实例-消息发送-方法合并-5

5.重构实例-消息发送-方法合并 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 经过前两轮的重构之后,已经提取了抽象接口,并将其static去掉。还为消息发送接口添加了转换方法。经过这几轮的修改,代码已经看起来整洁、 清晰了许多。那还有槽点吗? public class MessageSender { public void sendMessage(Stri

bug_null的博客 243

CAP 消息机制完全指南:消息定义、发送消费、补偿回调与重试清理策略

本篇文章以 .NET 分布式事务解决方案 CAP(基于最终一致性的微服务消息总线)中的消息(Message)机制为核心,系统讲解 CAP 中消息的数据结构、发送与消费方式、基于 `callbackName` 的补偿事务、异构系统集成时的 Header/Body 协议,以及消息的调度、存储、重试与数据清理策略。读完本文,你将能够完整掌握 CAP 消息的端到端生命周期,并可以直接将回调补偿、异构系统对

gitblog_00617的博客 424

OpenHuman Subconscious Factory 重构(Phase 5)落地指南:测试矩阵、文档同步与多实例发布策略

> 本指南围绕 [docs/plans/subconscious-factory/phase-5-tests-and-docs.md](https://link.gitcode.com/i/5b8926be64bc591e4514b36996083261) 展开:它是"Subconscious factory"(一个反射引擎、多个 world 实例)重构计划的验收与发布关卡。Phase 5 不新增

gitblog_00224的博客 412

Spring多实例注入全解析:List、Map、数组及排序策略

在Java工程实践中,依赖注入是Spring框架的核心能力,但当接口存在多个实现类时,按类型注入单个Bean往往会触发NoUniqueBeanDefinitionException。理解这一异常背后的容器解析逻辑,是掌握多实例注入的前提。Spring支持通过List、Map、数组等集合形态一次性收集全部候选Bean,并借助@Order、Ordered接口、@Priority等机制控制执行顺序。这种方式天然适用于策略模式、责任链、渠道分发等需要动态路由或批量处理的业务场景。与传统的if-else分支相比,集合

weixin_33428613的博客 239

策略模式实战指南:从if-else重构到优雅的算法替换

设计模式如何帮助开发者摆脱复杂的条件分支?策略模式作为面向对象核心模式之一,将一组可互换的算法封装为独立策略类,通过上下文统一调用,实现行为动态切换。其本质是利用接口解耦“算法定义”与“算法使用”,从而降低类间依赖、提升代码复用性,并满足开闭原则。在Java工程实践中,无论是支付渠道对接、折扣规则计算、消息推送分发,还是导出格式切换,策略模式都能替代不断膨胀的if-else,让新增业务变成纯粹的增量开发。结合工厂模式、Map与Lambda,或者Spring容器注入,可以进一步简化策略的组织与路由。本文结合真

weixin_31421613的博客 284

Java策略模式实战:从支付if-else到Spring优雅重构

在软件工程中,如何让代码面对不断变化的需求保持灵活与可维护,是开发者持续探索的核心课题。设计模式中的策略模式,正是为解决算法族与调用方的耦合而生的经典方案。它通过定义统一的策略接口,将不同的实现封装为独立类,使上下文可以在运行时自由切换行为,从而遵循开闭原则,提升系统的扩展性。在电商支付、优惠计算、消息推送等典型场景中,策略模式能有效替代冗长的条件分支,让新增业务只需添加新的策略类而无需修改旧代码。结合Java语言特性,无论是基于Map与Lambda的轻量实现,还是Spring框架下的Bean自动注入,都让

weixin_28730927的博客 274

500行if-else如何用策略模式重构为10行代码

在软件开发中,代码重构是持续演进的核心手段。当一段业务逻辑充斥着大量if-else嵌套时,每一次需求变更都意味着高成本与高风险。策略模式作为经典设计模式,通过将“判断”与“执行”解耦,将复杂的条件路由转换为可插拔的策略实现,从根本上提升系统可维护性与扩展性。该模式尤其适合用户类型、支付渠道等有限枚举值的映射场景,常见于风控、支付、消息推送等领域。本文以真实项目为例,展示如何利用枚举、策略接口与工厂Map,将500行if-else精简为10行核心路由代码,并分享设计取舍、Spring容器注入、单元测试与灰度发

weixin_33563728的博客 313

Spring反射+策略模式Demo

一、简述 日常开发中,会遇见类似于使用不同方式发送消息,例如:邮件、短信。再或者碰见文章分享之类的需求。那么我们平时如果不是用设计模式来做的情况下,会出现很多个 if-else 或者 switch 语句块。这样的话,代码耦合性也会非常高,将来再增加一个需求,则会导致一直增加判断语句块。也违反了面向对象的开闭原则。那么我们有什么好的解决方式呢?今次,则用反射+策略模式来重构一下代码,使之更加灵活。 二、不使用反射的策略模式 抽象策略角色(接口) publicinterfaceMyStragtegy{

JAVA一木的博客 360
上一篇: 重构实例-消息发送-方法合并-5
下一篇: 重构实例-消息发送-使用策略进行重构-枚举方式-7
null_null_bug
博客等级 码龄7年 72粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值