首页/开发/代码质量与评审速查/坏味道:基本类型偏执(Primitive Obsession)
重构手法62 条

坏味道:基本类型偏执(Primitive Obsession)

用 int / String 表示领域概念(金额、电话、币种):类型即约束,替换为 Replace Primitive with Object / Replace Type Code with Class 后,校验与格式逻辑有归属,调用处更难传错。

什么是基本类型偏执

基本类型偏执指用整数、字符串这类基本类型表达领域概念:金额、电话、币种、标识符。代价是约束完全靠调用方自觉,校验与格式逻辑四处复制,参数顺序写错也照样编译通过。处方是用以对象替换基本类型、以类替换类型码,让类型系统参与防错。

基本信息

典型信号到处是裸字符串与魔法数字,校验散落在调用方
处方以对象替换基本类型、以类替换类型码
收益校验与格式逻辑有归属,参数传错编译即报错
相邻问题数据泥团、只装数据的新类型
前提该概念有行为或约束,值得单独建模

典型使用场景

  • 金额与币种用裸数值传递,单位不统一难以发现
  • 手机号与邮箱在各层反复用正则校验
  • 类型代码用整数表示,靠注释说明取值范围
  • 文件路径与链接用字符串拼接,转义问题频发
  • 日期与时长用字符串传递,格式依赖口头约定

替换前后

替换前后
// 之前:任何字符串都能传进来,校验散落在各处
String raw = request.param(PHONE);
if (!raw.matches(PHONE_PATTERN)) { throw new IllegalArgumentException(); }

// 之后:类型即约束,构造时校验一次
PhoneNumber phone = PhoneNumber.parse(raw);
// 相等性、格式化、脱敏都在 PhoneNumber 内部实现

值得建类型吗

概念特征建议理由
有格式或取值范围约束建类型校验只写一次,调用方无法绕过
有可计算行为建类型行为与数据同处,重复逻辑消失
仅作为透传标签先不建多一层包装只增加转换成本
判定标准很实用:这个概念有没有校验规则或计算行为?有,就值得建类型;如果它只是从数据库透传到前端的标签,包装反而增加转换成本。
值对象尽量做成不可变:可变值对象会让相等性判断、缓存与集合去重出现反直觉行为,这类缺陷排查代价很高。

易错点

  • 为每个字符串都造类型:过度建模,转换代码与维护成本超过收益
  • 值对象做成可变:相等性与缓存假设被破坏,集合去重出现意外结果
  • 建了类型但校验仍留在调用方:类型没起到约束作用,只是换了写法
  • 只改类型不管序列化边界:数据库与接口层缺乏转换,问题留到运行期

数据来源与参考

  • 《重构》第 2 版 · 第 3 章(Primitive Obsession)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌