典型反模式深度解析及重构方案
反模式 1:魔法数字/字符串(Magic Numbers/Strings)
▐ 问题场景
// 订单状态校验
if (order.getStatus() == 3) { // 3代表已发货?sendNotification();
}// 折扣计算
double discount = price * 0.15; // 0.15是什么?
危害:
- 可读性差,维护者需要猜测数字含义
- 修改时需要全局搜索,容易遗漏
- 业务规则分散,违反单一真相源原则
▐ 重构方案
步骤 1:常量替换
// 创建常量类
public class OrderConstants {public static final int STATUS_SHIPPED = 3;public static final double VIP_DISCOUNT_RATE = 0.15;
}// 使用常量
if (order.getStatus() == OrderConstants.STATUS_SHIPPED) {sendNotification();
}double discount = price * OrderConstants.VIP_DISCOUNT_RATE;
步骤 2:进阶枚举化(适合有逻辑关联的状态)
public enum OrderStatus {CREATED(1), PAID(2), SHIPPED(3), COMPLETED(4);private final int code;OrderStatus(int code) {this.code = code;}public static OrderStatus fromCode(int code) {return Arrays.stream(values()).filter(status -> status.code == code).findFirst().orElseThrow(IllegalArgumentException::new);}
}// 使用枚举
if (order.getStatus() == OrderStatus.SHIPPED) {sendNotification();
}
步骤 3:配置中心化(适合频繁变更的参数)
# application.properties
discount.vip.rate=0.15
@Value("${discount.vip.rate}")
private double vipDiscountRate;
▐ 检测工具
- SonarQube 规则:
squid:S109
(魔法数字检测) - IDEA 插件:
MagicConstant
(自动提示替换)
反模式 2:神对象(God Object)
▐ 问题场景
public class OrderProcessor {// 处理订单逻辑public void process(Order order) { /* 200行逻辑 */ }// 数据库操作public void saveToDB(Order order) { /* 直接JDBC操作 */ }// 日志记录private void log(String message) { /* 自定义日志格式 */ }// 发送短信public void sendSMS(String phone) { /* 调用第三方API */ }
}
危害:
- 单文件代码量超过1000行
- 牵一发而动全身,修改风险高
- 无法单独测试某个功能模块
▐ 重构方案
步骤 1:职责拆分
// 领域对象
public class Order {// 订单核心属性与方法
}// 持久化层
@Repository
public class OrderRepository {public void save(Order order) { /* JPA实现 */ }
}// 服务层
@Service
public class OrderService {private final OrderRepository repository;private final NotificationService notificationService;public void processOrder(Order order) {// 核心业务逻辑repository.save(order);notificationService.sendSMS(order.getUser());}
}// 基础设施层
@Service
public class NotificationService {public void sendSMS(String phone) { /* 调用第三方API */ }
}
步骤 2:依赖注入
// 使用Spring的构造函数注入
@Service
public class OrderService {private final OrderRepository repository;private final NotificationService notificationService;public OrderService(OrderRepository repository, NotificationService notificationService) {this.repository = repository;this.notificationService = notificationService;}
}
步骤 3:领域驱动设计
// 订单聚合根
public class Order {public void ship() {validateShippingConditions();this.status = OrderStatus.SHIPPED;}
}// 领域服务
public class ShippingService {public void scheduleShipping(Order order) {order.ship();// 调度物流系统}
}
▐ 重构指标验证
- 类行数:从 1000+ 行 → 每个类 < 300 行
- 单元测试覆盖率:从 10% → 85%+
- 依赖关系:从 20+ 个依赖 → 每个类 < 5 个依赖
反模式 3:霰弹式修改(Shotgun Surgery)
▐ 问题场景
当需要修改用户身份验证规则时,需要改动:
1. LoginController.java
2. UserService.java
3. AuthFilter.java
4. SecurityConfig.java
5. audit.log
根本原因:
- 认证逻辑分散在多个层
- 没有统一的认证抽象
▐ 重构方案
步骤 1:建立防腐层
public interface AuthenticationGateway {User authenticate(String username, String password);
}@Component
public class DefaultAuthGateway implements AuthenticationGateway {// 集中实现所有认证逻辑
}
步骤 2:统一调用点
// 所有认证入口调用网关
@Controller
public class LoginController {private final AuthenticationGateway authGateway;public void login(String user, String pwd) {User user = authGateway.authenticate(user, pwd);// ...}
}// 过滤器
public class AuthFilter {private final AuthenticationGateway authGateway;public void doFilter() {User user = authGateway.authenticate(...);// ...}
}
步骤 3:策略模式扩展
public class OAuthAuthentication implements AuthenticationGateway {// 实现OAuth认证
}// 通过配置切换实现
@ConditionalOnProperty(name = "auth.mode", havingValue = "oauth")
@Component
public class OAuthAuthConfig {@Beanpublic AuthenticationGateway authGateway() {return new OAuthAuthentication();}
}
▐ 重构效果验证
- 修改点:从 5 个文件 → 1 个接口+1 个实现类
- 测试用例:只需修改网关的单元测试
- 扩展性:新增认证方式无需修改业务代码
反模式改进工作台
反模式 | 重构技术 | 风险指数 | 预计工时 | 关键检查点 |
---|---|---|---|---|
魔法数字 | 常量提取+配置中心 | ★☆☆☆☆ | 2h | 确保全量替换 |
神对象 | DDD分层+依赖倒置 | ★★★☆☆ | 8h | 接口隔离测试 |
霰弹式修改 | 防腐层+策略模式 | ★★☆☆☆ | 4h | 回归测试覆盖所有调用点 |
重构验证 Checklist
-
功能等价性:
- 新旧版本输出结果完全一致
- 所有边界条件测试通过
-
质量提升:
- 圈复杂度降低30%以上
- 单元测试覆盖率 ≥ 80%
-
可维护性:
- 新增功能只需修改1个文件
- 关键类有清晰的接口文档
相关文章:
典型反模式深度解析及重构方案
反模式 1:魔法数字/字符串(Magic Numbers/Strings) ▐ 问题场景 // 订单状态校验 if (order.getStatus() 3) { // 3代表已发货?sendNotification(); }// 折扣计算 double discount price * 0.15; // 0.15是什么?…...
神经探针与价值蓝海:AI重构需求挖掘的认知拓扑学
当产品经理的决策边界遭遇量子态的用户需求,传统需求分析工具已显露出经典物理般的局限性。Gartner 2024报告揭示:全球Top 500企业中有83%遭遇需求洞察的"测不准困境"——用户声称的需求与行为数据偏差率达47%,而未被表达的潜在需求…...
Tomcat 负载均衡
目录 二、Tomcat Web Server 2.1 Tomcat 部署 2.1.1 Tomcat 介绍 2.1.2 Tomcat 安装 2.2 Tomcat 服务管理 2.2.1 Tomcat 启停 2.2.2 目录说明 2.2.3编辑主页 2.3 Tomcat管理控制台 2.3.1开启远程管理 2.3.2 配置远程管理密码 三、负载均衡 3.1 重新编译Nginx 3.1.1 确…...
CSS >子元素选择器和空格
在 CSS 中,> 符号是 子元素选择器(Child Combinator),它用于选择某个元素的直接子元素(仅限第一层嵌套的子元素,不包含更深层的后代元素)。 语法 父元素 > 子元素 {样式规则; } 示例 …...
duckdb源码阅读学习路径图
🧭 DuckDB 最小内存源码阅读路径图 1️⃣ 数据流入口与批处理:DataChunk 项目内容✅ 目标理解 DuckDB 向量化执行的数据载体结构,如何影响内存📁 路径src/common/types/data_chunk.cpp/hpp🔍 入口函数DataChunk::Initialize, DataChunk::SetCardinality, Reset📌 优化…...
C#二叉树
C#二叉树 二叉树是一种常见的数据结构,它是由节点组成的一种树形结构,其中每个节点最多有两个子节点。二叉树的一个节点通常包含三部分:存储数据的变量、指向左子节点的指针和指向右子节点的指针。二叉树可以用于多种算法和操作,…...
BT-Basic函数之首字母W
BT-Basic函数之首字母W 文章目录 BT-Basic函数之首字母Wwaitwait for start wait wait函数使程序在执行下一个功能之前暂停指定的秒数。 语法 wait <数值表达式>参数 <数值表达式> 等待时长,以秒为单位。该值必须大于或等于0。小于25毫秒的正值会被…...
如何避免论文内容被误认为是 AI 生成的?
AIGC 检测的原理 AIGC 检测主要基于自然语言处理(NLP)和机器学习技术,通过深度分析文本内容来识别其中的 AI 生成痕迹。具体原理如下: 基础学习算法:利用机器学习算法对文本信息进行特征提取和表示,以便计…...
node.js之path常用方法
node.js之path常用方法 1.path.join([…paths]) 用于将多个路径片段拼接成一个路径,会自动处理路径分隔符,避免手动拼接时可能出现的问题 const joinedPath path.join(folder1, folder2, file.txt); console.log(joinedPath); // 输出: folder1/fol…...
【面试】C++与C override的报错阶段 RAII
文章目录 C 相对于 C 语言的主要区别**1. 面向对象编程(OOP)****2. 函数增强****3. 内存管理****4. 引用(Reference)****5. 标准模板库(STL)****6. 异常处理****7. 类型安全增强****8. 其他特性****9. 兼容…...
LeetCode 3396.使数组元素互不相同所需的最少操作次数:O(n)一次倒序遍历
【LetMeFly】3396.使数组元素互不相同所需的最少操作次数:O(n)一次倒序遍历 力扣题目链接:https://leetcode.cn/problems/minimum-number-of-operations-to-make-elements-in-array-distinct/ 给你一个整数数组 nums,你需要确保数组中的元素…...
机器学习课堂7用scikit-learn库训练SVM模型
1.用scikit-learn库训练SVM模型 代码 # 2-11用scikit-learn库训练SVM模型 import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn import svm # 导入sklearn# 参数设置 m_train 250 # 训练样本数量 svm_C 100 # SVM的C值 svm_kernel …...
模拟考试系统(ssm+vue+mysql5.x)
模拟考试系统(ssmvuemysql5.x) 模拟考试系统是一个为考试准备和管理提供全面支持的平台。系统提供了丰富的功能模块,包括个人中心、科目管理、复习资料管理、参考文献管理、用户管理、留言板管理、试题管理、试卷管理、系统管理和考试管理。用户可以在个人中心修改…...
【计网】作业4
一. 单选题(共22题,64分) 1. (单选题)主机甲采用停止-等待协议向主机乙发送数据,数据传输速率是4kb/s,单向传播时延为30ms,忽略确认帧的发送时延。当信道利用率等于80%时,数据帧的长度为&#…...
MYSQL数据库语法补充
一,DQL基础查询 DQL(Data Query Language)数据查询语言,可以单表查询,也可以多表查询 语法: select 查询结果 from 表名 where 条件; 特点: 查询结果可以是:表中的字段…...
Java基础编程练习第38题-除法器
题目:编写一个除法器,输入被除数和除数,并将结果输出。 这道题看似很简单,实则也不难。 就是假如用户输入的类型不同怎么办呢?用户输入int或者double类型应该怎么解决。这里我们就需要用到函数的重载。 代码如下&am…...
【基于Vue3组合式API的互斥输入模式实现与实践分享】
基于Vue3组合式API的互斥输入模式实现与实践分享 目录 背景与痛点设计思路技术实现使用场景与案例遇到的问题与解决方案最佳实践总结 1. 背景与痛点 在表单交互设计中,我们经常面临这样的场景:多种输入方式互斥。例如,在评分系统中&#…...
Linux进程概念及理解
目录 冯诺依曼体系结构 操作系统(Operator System) 概念 设计OS的目的 定位 如何理解 "管理" 总结 系统调用和库函数概念 进程 基本概念 描述进程-PCB task_struct-PCB的一种 task_ struct内容分类 组织进程 查看进程 通过系统调用获取进程标示符 通过系统调用创建进…...
苹果签名是否安全
苹果开发者与运营商都对苹果签名有一定了解,那么苹果签名安全吗?下面我来跟大家聊一聊。 苹果签名能验证应用的来源,但存在一些风险,有开发者伪造签名,让用户认为此产品是可信的,这样就安装到了恶意应用&am…...
STM32在裸机(无RTOS)环境下,需要手动实现队列机制来替代FreeRTOS的CAN发送接收函数
xQueueSendToBackFromISR(ecuCanRxQueue, hcan->pRxMsg, &xHigherPriorityTaskWoken),xQueueReceive(mscCanRxQueue,&mscRxMsg,0)和xQueueSendToBack(mscCanTxQueue, &TxMessageTemp, 0 )这3个函数,在裸机下实现: 在裸机&…...
无法看到新安装的 JDK 17
在 Linux 系统中使用 update-alternatives --config java 无法看到新安装的 JDK 17,可能是由于 JDK 未正确注册到系统备选列表中。 一、原因分析 JDK 未注册到 update-alternatives update-alternatives 工具需要手动注册 JDK 路径后才能识别新版本。如果仅安装 JDK…...
JavaEE——线程的状态
目录 前言1. NEW2. TERMINATED3. RUNNABLE4. 三种阻塞状态总结 前言 本篇文章来讲解线程的几种状态。在Java中,线程的状态是一个枚举类型,Thread.State。其中一共分为了六个状态。分别为:NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING, TERMI…...
数据结构与算法-数学-(同余,线性同余方程,中国剩余定理,卡特兰数,斯特林数)
同余方程: 1.1 线性同余方程 & 乘法逆元 线性同余方程是形如 ax≡b(mod m) 的方程,可转化为 axmyb 的线性不定方程,利用扩展欧几里得算法求解。当 b1 时,x 就是 a 在模 m 意义下的乘法逆元。 代码: #include &…...
RAG 系统中的偏差是什么?
检索增强生成 (RAG) 在减少模型幻觉和增强大型语言模型 (LLM)的领域特定知识库方面已获得广泛认可。通过外部数据源佐证大型语言模型生成的信息,有助于保持模型输出的新鲜度和真实性。然而,最近在 RAG系统中的发现,突显了基于 RAG 的大型语言…...
[创业之路-362]:用确定性的团队、组织、产品开发流程和方法,应对客户、市场、竞争和商业模式的不确定性。
在充满不确定性的商业环境中,通过确定性的团队、组织、产品开发流程和方法构建核心竞争力,是应对客户、市场、竞争和商业模式变化的核心策略。以下从团队韧性、组织敏捷、产品开发闭环三个维度,结合实战方法论,提供可落地的解决方…...
系统与网络安全------网络通信原理(1)
资料整理于网络资料、书本资料、AI,仅供个人学习参考。 文章目录 网络通信模型协议分层计算机网络发展计算机网络功能什么是协议为什么分层邮局实例 OSI模型OSI协议模型OSI七层模型OSI七层的功能简介 TCP/IP模型OSI模型与TCP/IP模型TCP/IP协议族的组成各层PDU设备与…...
ArkTS语言基础之函数
前言 臭宝们终于来到了ArkTS基础之函数,今天我们来学习一下ArkTS的函数的相关知识,上一节中也有一些函数的基础知识。 函数声明 函数声明引入一个函数,包含其名称、参数列表、返回类型和函数体,在下面的例子中,我们声明了一个名…...
synchronized锁升级的锁对象和Mark Word
在讨论synchronized锁升级和Mark Word时,提到的"对象"通常指的是锁对象,也就是被用作synchronized同步锁的那个Java对象。 1. 什么是锁对象? 锁对象是指被用于synchronized同步代码块或方法的对象实例。例如: // 这个…...
数据结构|排序算法(二)插入排序 希尔排序 冒泡排序
一、插入排序 1.算法思想 插入排序(Insertion Sort)是一种简单的排序算法,其基本思想是:将待排序的元素插入到已经有序的序列中,从而逐步构建有序序列。 具体过程如下: 把待排序的数组分为已排序和未排…...
12、主频和时钟配置实验
一、I.MX6U 时钟系统详解 1、系统时钟来源 开发板的系统时钟来源于两部分: 32.768KHz 和24MHz 的晶振,其中 32.768KHz 晶振是 I.MX6U 的 RTC 时钟源, 24MHz 晶振是 I.MX6U 内核和其它外设的时钟源。 2、7路PLL时钟源 I.MX6U 的外设有很多,不同的外设时钟源不同, NXP 将…...
DFS和BFS的模版
dfs dfs金典例题理解就是走迷宫 P1605 迷宫 - 洛谷 dfs本质上在套一个模版: ///dfs #include<bits/stdc.h> using namespace std; int a[10][10]{0}; int m,n,t,ans0; int ex,ey; int v[10][10]{0}; int dx[4]{-1,0,1,0}; int dy[4]{0,1,0,-1}; void dfs(in…...
docker镜像导出导入
在Docker中,可以很容易地导出和导入镜像,这对于备份、迁移或者在不同的环境中共享镜像非常有用。以下是操作步骤: 导出镜像 使用 docker save docker save 命令可以用来将一个或多个镜像保存到一个文件中,这个文件可以被导入到任…...
大模型Agent | 构建智能体 AI-Agent的 5大挑战,及解决方案!
源自: AINLPer(每日干货分享!!) 编辑: ShuYini 校稿: ShuYini 时间: 2025-4-7 更多:>>>>专注大模型/AIGC、学术前沿的知识分享! 引言 AI-Agent正变得越来越智能,它能够根据用户需…...
基于STM32、HAL库的IP2721 快充协议芯片简介及驱动程序设计
一、简介: IP2721是一款高性能的USB PD (Power Delivery)协议控制器芯片,主要用于USB Type-C接口的电源管理。它支持USB PD 3.0规范,能够实现多种电压和电流的协商,广泛应用于充电器、移动电源等设备。 主要特性: 支持USB PD 3.0规范 支持Type-C接口的DRP/SRC/SNK模式 内…...
荣耀90 GT信息
外观设计 屏幕:采用 6.7 英寸 AMOLED 荣耀绿洲护眼屏,超窄边框设计,其上边框 1.6mm,左右黑边 1.25mm,屏占较高,带来更广阔的视觉体验。屏幕还支持 120Hz 自由刷新率,可根据使用场景自动切换刷新…...
53. 评论日记
要自己有判断是非的能力宝子们。#小米 #小米su7 #雷军 #神操作 #小米su7ultra_哔哩哔哩_bilibili 2025年4月8日19:30:57...
【10】搭建k8s集群系列(二进制部署)之安装Dashboard和CoreDNS
一、部署Dashboard 1.1、创建kubernetes-dashboard.yaml文件 完整的yaml配置文件信息如下: # Copyright 2017 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in …...
【算法手记12】DP25 删除相邻数字的最大分数
🦄个人主页:修修修也 🎏所属专栏:刷题 ⚙️操作环境:牛客网 目录 一.DP25 删除相邻数字的最大分数 题目详情: 题目思路: 解题代码: 结语 一.DP25 删除相邻数字的最大分数 牛客网题目链接(点击即可跳转):DP25 删除相邻数字的最大分数 题目详情: 本题详情如…...
[Godot] C#简单实现人物的控制和动画
目录 实现效果 场景搭建 脚本实现 移动 动画 完整脚本 相机跟随 总结 实现效果 场景搭建 本文章只分享了关于移动和动画的,没有给碰撞体,大家根据需要自行添加吧 相机的缩放大小可以根据自己的需要调整 我的人物动画结构是这样的,待机动…...
选择站群服务器租用的优势都有什么?
站群服务器是一种专门用于托管多个网站的服务器,是通过集中管理和资源分配,可以支持同时运行数十个甚至是数百个独立网站,站群服务器的主要特点就是让每个网站可以分配独立的IP地址,避免出现IP关联风险,通过统一控制面…...
VS Code下开发FPGA——FPGA开发体验提升__下
上一篇:IntelliJ IDEA下开发FPGA-CSDN博客 Type:Quartus 一、安装插件 在应用商店先安装Digtal IDE插件 安装后,把其他相关的Verilog插件禁用,避免可能的冲突。重启后,可能会弹出下面提示 这是插件默认要求的工具链&a…...
leetcode13.罗马数字转整数
遍历,下一个值不大于当前值就加上当前值,否则就减去当前值 class Solution {public int romanToInt(String s) {Map<Character, Integer> map Map.of(I, 1,V, 5,X, 10,L, 50,C, 100,D, 500,M, 1000);int sum 0;for (int i 0; i < s.length(…...
WVP-PRO配置与部署
ZLMediaKit部署与配置 https://blog.csdn.net/qq_38179971/article/details/147043763MySQL8.0.13安装[Ubuntu16.04] cd /usr/local/src wget http://soft.vpser.net/lnmp/lnmp1.6.tar.gz -cO lnmp1.6.tar.gz && tar zxf lnmp1.6.tar.gz && cd lnmp1.6 &…...
opencv图像库编程
目录 一、Linux搭建C OpenCV开发环境1.安装必要依赖项2.安装opencv3、cmake分析4、验证安装 二、编写一个打开图片进行特效显示的代码 test.cpp1.gcc方式编译1)在opencv3.4.5下新建mytest文件夹2)创建test.cpp3)编译 2.makemakefile方式编译3…...
【Easylive】定时任务-每日数据统计和临时文件清理
【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版 这个定时任务系统主要包含两个核心功能:每日数据统计和临时文件清理。下面我将详细解析这两个定时任务的实现逻辑和技术要点: Component Slf4j public class SysTas…...
搜广推校招面经七十
美团暑期推荐实习 一、讲一下self-attention,qkv的含义。 见【搜广推校招面经五】 二、讲一下协同过滤召回,新闻推荐项目为什么不用usercf? 见【搜广推校招号面经六十四】 三、介绍信息增益公式(Information Gain) 见【搜广…...
TypeScript 泛型详解及应用场景
泛型(Generics)是 TypeScript 的核心特性,它允许我们编写可复用、类型安全的代码,同时保持灵活性。以下是深度解析和实际应用指南: 一、泛型基础概念 本质:参数化类型,将类型作为变量传递&…...
Proximal Policy Optimization (PPO)2017
2.1 策略梯度方法 策略梯度方法计算策略梯度的估计值并将其插入到随机梯度上升算法中。最常用的梯度估计器的形式如下: g ^ E t [ ∇ θ log π θ ( a t ∣ s t ) A ^ t ] (1) \hat{g} \mathbb{E}_t \left[ \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \h…...
使用 Google ML Kit 实现图片文字识别(提取美国驾照信息)
Google ML Kit 是一个现代、功能强大、跨平台的机器学习 SDK。在这篇文章中,我们将使用 ML Kit 在 Android 应用中识别图片文字,以提取美国驾照上的关键信息:DL(驾照号) 和 EXP(有效日期)。 &am…...
VR体验馆如何用小程序高效引流?3步打造线上预约+团购裂变系统
VR体验馆如何用小程序高效引流?3步打造线上预约团购裂变系统 一、线上预约的核心价值:优化体验,提升转化 减少客户等待时间 通过小程序预约功能,客户可提前选择体验时段,避免到店排队。数据显示&#…...