重构手法——函数行为重塑类 | 语意 | 用对象替换基本类型

50 阅读2分钟

简介

"用对象替换基本类型"是提升领域建模能力的关键重构手法。通过将简单值类型封装为领域对象,可以赋予数据相关行为,增强类型安全性并减少"基本类型偏执"坏味道。

针对的症状(代码坏味道)

  • 基本类型数据需要关联行为操作
  • 相同含义的值在多处重复验证
  • 存在表示领域概念的原始值
  • 需要封装数据校验规则

用对象替换基本类型的详细步骤

  1. 创建值对象类
    • 声明final字段存储原始值
    • 添加参数校验构造方法
  2. 迁移相关行为
    • 将处理该值的函数移至新类
    • 保持原始值的不可变性
  3. 替换类型引用
    • 用新对象替换原始类型声明
    • 更新相关的getter/setter
  4. 保持兼容接口
    • 添加toPrimitive()转换方法
    • 重写toString()/equals()等方法

示例

重构前代码:

class Customer {
    private String zipCode; // 格式:123-4567

    boolean isValidZipCode() {
        return zipCode.matches("\\d{3}-\\d{4}");
    }

    String getDeliveryRegion() {
        return zipCode.substring(0, 3);
    }
}

重构步骤:

  1. 创建ZipCode值对象:

    class ZipCode {
        private final String value;
    
        public ZipCode(String value) {
            if (!value.matches("\\d{3}-\\d{4}")) {
                throw new IllegalArgumentException("Invalid zipcode format");
            }
            this.value = value;
        }
    
        String getRegion() {
            return value.substring(0, 3);
        }
    
        @Override
        public String toString() {
            return value;
        }
    }
    
  2. 重构Customer类:

    class Customer {
        private ZipCode zipCode;
    
        boolean isValidZipCode() {
            return zipCode != null;
        }
    
        String getDeliveryRegion() {
            return zipCode.getRegion();
        }
    }
    

练习

基础练习题

  1. 简单类型替换

    // 重构前
    class Product {
        private String sku; // 格式:CAT-001
    }
    

进阶练习题

  1. 带行为的值对象

    // 重构前
    class Order {
        double calculateTax(double amount, String countryCode) {
            if ("US".equals(countryCode)) return amount * 0.07;
            if ("JP".equals(countryCode)) return amount * 0.08;
            return 0;
        }
    }
    

综合拓展练习题

  1. 复合值对象

    // 重构前
    class Person {
        private String idNumber; // 包含生日、性别等信息
    
        int getBirthYear() {
            return Integer.parseInt(idNumber.substring(0, 4));
        }
    }
    

代码审查要点

  1. 优点:

    • 增强领域模型表现力
    • 集中数据校验逻辑
    • 避免基本类型滥用
  2. 潜在问题:

    • 控制值对象膨胀
    • 保持合理的构造成本
    • 注意序列化兼容性