DRY原则 代码复用实战指南|避免重复提升开发效率核心技巧

DRY原则 代码复用实战指南|避免重复提升开发效率核心技巧 一

文章目录CloseOpen

先学会揪出代码里的重复”隐形杀手”

很多人觉得”重复代码”就是一眼能看到的复制粘贴,其实远不止。我去年带一个电商项目时,有个新人写支付模块,把订单状态判断逻辑在5个接口里各写了一遍,后来产品要加一种新状态,我们改了3天才改完所有地方,还漏了一个接口导致线上bug。后来复盘时发现,那些藏得深的”隐形重复”才最坑,比如看似不同的代码里藏着相同的业务规则,或者重复的参数校验逻辑。

要识别这些”隐形杀手”,你可以从三个维度排查。第一个是业务逻辑重复,比如用户登录时的token校验、订单提交前的库存检查,这些跨接口的相同逻辑最容易被忽略。我通常会让团队用”关键词搜索法”——在IDE里搜业务相关的关键词,比如”订单状态”,如果结果超过3处,基本就能确定有重复。第二个是技术实现重复,像日期格式化、JSON解析这类通用功能,没必要每个类都写一遍。第三个是配置信息重复,比如数据库连接地址、API密钥,硬编码在代码里不仅重复,还不安全。

为了让你更直观,我整理了一个表格,是我带团队时 的”重复代码的5个典型信号及识别方法”,你可以对照着检查自己的项目:

信号类型 识别特征 常见场景 处理优先级
业务规则重复 相同的if-else判断逻辑出现在3个以上文件 订单状态流转、权限校验 最高
工具方法重复 功能相同的函数名不同(如formatDate/dateFormat) 日期处理、字符串转换
硬编码重复 魔法值(如数字0/1代表状态)多次出现 状态码、错误提示文案
异常处理重复 相同的try-catch逻辑包裹不同业务代码 数据库操作、API调用
配置信息重复 同一URL/密钥在多个类中定义 第三方API地址、数据库连接串

你可能会说,”我知道重复不好,但有时候赶项目进度,复制粘贴最快啊!”其实我以前也这么想,直到有次做一个物流系统,为了赶上线,把地址解析逻辑复制到4个模块里。后来客户说要支持海外地址格式,我们光是改这些重复代码就花了两天,还因为漏改一个地方被投诉。从那以后,我团队里就有个不成文的规矩:只要一段代码复制超过2次,必须停下来做复用,哪怕多花半小时,后面能省十倍时间。

三种落地DRY原则的实战技巧,我带团队时必用

识别出重复代码后,怎么复用才不会过度设计?我 了三个方法,都是经过项目验证的”懒人方案”,不用重构整个项目,小步快跑就能见效。

从”复制3次”开始的函数封装,新人也能上手

最基础也最有效的复用方式就是函数封装,但很多人容易犯两个错:要么拆得太细导致函数满天飞,要么干脆不拆。我的经验是,当一段代码重复出现3次以上,或者逻辑超过10行,就值得封装成函数。你别小看这个”3次原则”,我带过的新人按这个标准做,代码量平均减少了30%。

举个例子,之前团队里有个接口需要校验用户是否实名认证,一开始代码是这样的:

// 订单接口里的校验

if (user.getRealName() == null || user.getIdCard() == null) {

return Result.fail("请先实名认证");

}

// 提现接口里的校验

if (user.getRealName() == null || user.getIdCard() == null) {

return Result.fail("请先实名认证");

}

后来按”3次原则”,我们把它封装成函数:

public boolean checkRealName(User user) {

return user.getRealName() != null && user.getIdCard() != null;

}

现在不管多少个接口需要校验,直接调用这个函数就行。你发现没?封装的时候不用追求”完美设计”,先解决当前的重复问题,后面再慢慢优化。Martin Fowler在《重构》里说过”代码复用的本质是提取变化中的不变”,你可以先从这种”一眼就能看出来的重复”入手,等熟练了再处理更复杂的场景(原文链接:https://martinfowler.com/books/refactoring.html,已添加nofollow)。

用”工具类+常量类”搭骨架,我管这叫”代码复用基础设施”

如果说函数封装是”小颗粒复用”,那工具类和常量类就是”中颗粒复用”,能解决跨模块的重复问题。我带团队时,每个项目都会先搭两个基础类:一个CommonUtils放通用工具方法,一个Constants放所有常量,这就像给代码建了个”共享仓库”,谁要用直接拿。

比如日期处理,以前团队里有人用SimpleDateFormat,有人用LocalDateTime,格式还不统一。后来我们在CommonUtils里统一封装:

public class CommonUtils {

// 统一日期格式化

public static String formatDate(LocalDateTime date, String pattern) {

return DateTimeFormatter.ofPattern(pattern).format(date);

}

// 默认格式,避免重复传参

public static String formatDefaultDate(LocalDateTime date) {

return formatDate(date, "yyyy-MM-dd HH:mm:ss");

}

}

现在整个项目都用这两个方法,再也不会出现格式混乱的问题。常量类也一样,把所有状态码、错误提示都放进去:

public class Constants {

public static final int ORDER_STATUS_PAID = 1;

public static final String ERROR_NOT_REAL_NAME = "请先实名认证";

}

你可能会问,”常量类会不会变得特别大?”我的经验是按业务模块拆分,比如OrderConstantsUserConstants,这样既避免单个类臃肿,又能保持复用性。去年做一个金融项目时,我们光常量类就拆了5个,但开发效率反而提高了,因为大家不用再猜”这个状态码1代表什么”,直接看常量名就知道。

配置化开发:让”改代码”变成”改配置”,我用这招减少80%重复修改

如果你的项目里经常需要改业务规则,比如优惠活动规则、权限判断条件,那一定要试试配置化开发。简单说,就是把会变的逻辑写到配置文件或数据库里,而不是硬编码在代码中。我之前带一个电商项目,用这招把”改活动规则”的时间从2小时缩短到5分钟。

举个常见场景:不同会员等级对应不同折扣。硬编码的话可能是这样:

if (user.getVipLevel() == 1) {

discount = 0.9;

} else if (user.getVipLevel() == 2) {

discount = 0.8;

}

这种代码每次加新等级都要改代码、测试、上线。后来我们改成配置化,在数据库建一张vip_discount表:

vip_level discount min_points
1 0.9 1000
2 0.8 5000

然后写一个通用的查询方法:

public BigDecimal getDiscount(int vipLevel) {

// 从数据库查配置

return jdbcTemplate.queryForObject(

"select discount from vip_discount where vip_level = ?",

new Object[]{vipLevel},

BigDecimal.class

);

}

现在产品要加个”3级会员0.7折”,运营直接在后台改配置就行,不用开发动手。你看,这就是DRY原则的高阶应用——不仅复用代码,还复用”修改逻辑的流程”。 配置化不是万能的,简单的固定逻辑用函数封装就够了,复杂的业务规则才需要配置化,别为了复用而复用。

你可以先从项目里找那些”每个月都要改一次”的代码块,试试用配置化改造,我敢说第一次可能花点时间,但后面绝对越用越爽。上次我帮朋友的项目做优化,就把他们的优惠券规则改成了配置化,现在他们运营自己就能上线新活动,再也不用求着开发改代码了。

按这些方法做下来,你会发现代码不仅变少了,维护起来也轻松多了。记得别追求一步到位,先解决最扎眼的重复问题,慢慢迭代。如果你按这些方法试了,欢迎回来告诉我你的代码量减少了多少!


你问应用DRY原则会不会拖慢进度,我刚开始带团队时也纠结过这个问题。记得有次做一个客户管理系统,开发到一半,后端同学抱怨“封装工具类太费时间,不如直接复制粘贴快”。结果上线后客户要加个“手机号脱敏”功能,我们发现这个逻辑在7个接口里各写了一遍,硬生生改了一整天,还漏了个地方被客户投诉。后来复盘时算过账:当时如果花30分钟封装成工具类,后期改需求最多10分钟就能搞定,短期多花的那点时间,早就被长期维护的效率省回来了。所以我的经验是,刚开始确实可能多花5%到10%的时间在复用设计上,但只要项目周期超过两周,这笔“时间投资”绝对赚。

其实关键在“小步复用”,不用一开始就追求完美。你看,要是一段代码第一次出现,先不用急着封装;第二次出现时,你可以先标记一下“这里和之前XX处重复了”;到第三次出现,就必须停下来封装了——这是我团队的“三次原则”,特别适合怕麻烦的开发者。就像写API接口时,参数校验逻辑第一次写在A接口,第二次出现在B接口时,你心里记一下;第三次在C接口碰到,就花20分钟把它抽成一个校验函数。这样既不会因为过度设计耽误进度,又能避免重复代码堆积。而且在敏捷开发里,迭代周期短,需求变更多,复用的代码改起来只动一处,反而能让每个迭代的开发速度越来越快,你不用再把时间浪费在“改完这里改那里”的重复劳动上,团队自然有更多精力琢磨新功能怎么做得更好。


DRY原则和代码复用是一回事吗?

DRY原则(Don’t Repeat Yourself)是指导思想,核心是“避免重复逻辑”;代码复用是实现DRY原则的具体手段之一。简单说,DRY原则要求“同一个知识或逻辑在系统中只出现一次”,而代码复用通过函数封装、工具类、配置化等方式,让重复逻辑只需要写一次就能被多处调用。比如文章中提到的“订单状态判断逻辑”,复用是手段,最终目的是符合DRY原则,避免重复修改。

如何判断代码复用是否过度,反而导致复杂度上升?

可以参考“3次原则”和“收益成本比”:如果一段代码重复出现3次以上,或复用后能减少50%以上的重复劳动,就值得复用; 若重复次数少于2次,或为了复用而增加大量抽象(比如为10行代码建一个复杂框架),反而会让代码更难维护。我团队的经验是:先解决“明显的重复”(比如复制粘贴的代码块),再逐步优化“隐形重复”,避免为了“完美复用”而过度设计。

小项目或者短期项目有必要应用DRY原则吗?

非常有必要。小项目虽然功能简单,但重复代码带来的问题和大项目一样:比如改一个逻辑要改多个地方,新人接手时难以理解重复逻辑。我之前帮朋友做一个短期活动页面,初期为了赶进度复制了3处表单校验代码,后来需求变更,光是改这些重复代码就多花了1小时。 小项目至少做到“工具类复用”和“常量统一管理”,后期维护会轻松很多。

复用代码时遇到不同场景的细微差异,该怎么处理?

可以通过“参数化”或“配置化”解决。比如文章中提到的“会员折扣”场景,不同等级折扣不同,用数据库配置而非硬编码if-else;再比如日期格式化,封装函数时允许传入“格式参数”(如yyyy-MM-dd或MM/dd/yyyy),既能复用核心逻辑,又能适配不同场景。避免为了微小差异写重复代码,也不要为了强行复用忽略差异,保持“求同存异”的平衡。

应用DRY原则会拖慢开发进度吗?

短期可能会多花5%-10%的时间,但长期能节省50%以上的维护成本。我带团队时发现,前期花30分钟封装一个复用函数,后期改需求时至少能省2小时(不用改多个地方)。关键是用“小步复用”:先解决当前的重复问题,比如复制第2次时就停下来封装,不用等所有重复都出现。敏捷开发中,DRY原则反而能让迭代更快——因为重复劳动少了,团队能把时间花在新功能上。

0
显示验证码
没有账号?注册  忘记密码?