【代码坏味道】膨胀类 Bloaters
🐘 长方法(Long Method)
📍 什么是长方法?
一个函数(方法)写得太长了,比如超过了 10 行代码,就要开始警惕了。
❗ 为什么不好?
- 一开始只是加两行代码,觉得“没必要单独写个函数吧”,但一直加一直加,就变成“面条式代码”。
- 别人读这个函数会很费劲,自己写的时候也难维护。
✅ 怎么解决?
- 如果你想在方法里加注释解释某段逻辑,说明这段代码应该拆出去成单独方法。
- 哪怕是只有一行代码,如果需要说明,也应该单独封装成一个有意义的方法。
🔨 可以使用的技巧:
-
提取方法(Extract Method)
-
如果受限于变量,可以使用:
- 用查询代替临时变量(Replace Temp with Query)
- 引入参数对象(Introduce Parameter Object)
- 保留整个对象(Preserve Whole Object)
💰 好处:
- 小方法的代码更容易看懂、改动风险小。
- 重复代码也更容易被发现和删除。
- 不用担心“方法太多影响性能”,其实几乎没影响。
🏢 大类(Large Class)
📍 什么是大类?
一个类(类似于一块代码模块)里面包含太多变量、方法、代码行。
❗ 为什么不好?
- 类一开始很小,但功能一多,就越写越大。
- 程序员偷懒,喜欢往原来的类里加功能,而不是重新建一个类。
✅ 怎么解决?
-
把类拆成更小的类,一个类只负责一种职责。
-
使用:
- 提取类(Extract Class)
- 提取子类(Extract Subclass)
- 提取接口(Extract Interface)
- 如果是界面类太大,考虑拆成“界面类 + 数据类”
💰 好处:
- 更容易记住和管理类里的内容。
- 避免重复代码,代码结构更清晰。
⚙️ 原始类型痴迷(Primitive Obsession)
📍 什么是“痴迷”原始类型?
就是你过度使用 int、string 这些基本类型,而不愿意封装成对象。
比如:
- 电话号码用 string,金额用 float,而不是专门建个
PhoneNumber
或Money
类。 - 用常量
1, 2, 3
来表示权限等级,而不是定义角色类。
❗ 为什么不好?
- 这些基本类型不好加规则,也不好扩展。
- 常量意义不清晰,还容易出 bug。
✅ 怎么解决?
- 使用对象代替基本类型,比如把
price
封装成Money
类。 - 用类表示状态、角色,而不是数字或字符串。
- 参数多时,用类打包(Introduce Parameter Object)
💰 好处:
- 代码更灵活,规则清晰。
- 更容易找到重复代码,修改也集中,不怕出错。
📬 长参数列表(Long Parameter List)
📍 什么是长参数列表?
如果一个方法需要传超过 3~4 个参数,那就太多了。
❗ 为什么不好?
- 参数太多让方法调用变复杂,容易传错。
- 有时为了减少依赖,把对象提前创建好再传进来,结果传了一堆参数。
✅ 怎么解决?
- 如果多个参数来自一个对象,可以直接传这个对象(Preserve Whole Object)。
- 如果来自不同地方,但经常一起用,就打包成一个类(Introduce Parameter Object)。
💰 好处:
- 方法调用更简洁,代码更清晰。
- 还能发现重复逻辑,方便提取成公共方法。
🧱 数据泥团(Data Clumps)
📍 什么是数据泥团?
如果你在多个地方看到总是成组出现的变量(比如数据库连接的 host、port、user、pass),那就是一个“数据泥团”。
❗ 为什么不好?
- 这些变量成组出现,一变就全变,容易出错。
- 多次复制粘贴,非常不优雅。
✅ 怎么解决?
- 把这些成组变量封装进一个类,比如
DbConfig
。 - 如果是方法参数太多,也可以用“参数对象”。
💰 好处:
- 所有相关操作集中在一个类中,更好维护。
- 大大减少代码行数,也避免写重复的东西。
✅ 小结:什么时候该重构?
异味类型 | 表现 | 处理方式 |
---|---|---|
长方法 | 方法超过 10 行 | 拆方法、封装注释 |
大类 | 类里方法、变量太多 | 拆类、抽子类/接口 |
原始类型痴迷 | int/string 代替对象 | 用对象封装、引入类型 |
长参数列表 | 传参超过 4 个 | 保留整个对象或参数对象 |
数据泥团 | 相同变量反复出现 | 抽成类统一管理 |