使用DDD做参数检验

关于在实体类中进行参数校验的"优雅"方式,有一个叫做"领域驱动设计"(Domain-Driven Design,简称DDD)的方法,它推崇"丰富的模型"(Rich Model)。这种方法强调的是将业务规则和逻辑封装到实体或值对象中,使得它们不仅仅是数据的容器,而是拥有行为的完整模型。

基于这个思路,我们可以在实体类中定义相关的业务方法和校验方法:

1. **定义实体类,并在其中封装校验方法**

public class User {

    private String username;
    private int age;

    // ... 其他字段和getter/setter

    // 构造函数中进行校验
    public User(String username, int age) {
        setUsername(username);
        setAge(age);
    }

    public void setUsername(String username) {
        if (username == null || username.isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        this.username = username;
    }

    public void setAge(int age) {
        if (age <= 0) {
            throw new IllegalArgumentException("年龄必须大于0");
        }
        this.age = age;
    }

    // 可以添加其他与User相关的业务方法
    public void updateProfile(String newUsername, int newAge) {
        setUsername(newUsername);
        setAge(newAge);
    }
}
  1. 在服务层调用实体类的相关方法

这里,由于实体类的构造方法或者setter方法会进行参数校验,所以服务层的逻辑将变得非常简单和清晰。

@Service
public class UserService {

    public void createUser(String username, int age) {
        User user = new User(username, age);
        // ... 保存用户或其他业务逻辑
    }

    public void updateUserProfile(User user, String newUsername, int newAge) {
        user.updateProfile(newUsername, newAge);
        // ... 更新用户或其他业务逻辑
    }
}
  1. 在Controller层捕获并处理异常

Controller层的处理方式与前面相同,捕获异常并转换为合适的HTTP响应。

这种方式的好处是将数据和与数据相关的行为都封装在一起,形成一个真正意义上的"对象"。不仅可以用于参数校验,还可以封装更多的业务逻辑。当然,这也要求我们在设计实体类时更加小心,确保内部的状态始终保持一致和有效。