You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

领域驱动设计(DDD):如何更新值对象(ValueObject)?

值对象的不可变性与更新场景处理

值对象不是完全不能"修改",而是不能原地修改——它的核心是用属性值来定义自身的身份,不像实体那样靠唯一ID区分。你没办法改动一个已经创建好的值对象,但可以基于旧对象的内容,生成一个包含更新后数据的新值对象。

比如你说的带List<String> tags的Product值对象,正确的更新方式不是往原对象的标签列表里加新标签,而是创建一个新的Product实例,把旧标签加上新标签组成的新列表传进去。

至于为什么要把字段设为final、集合设为不可修改:这是从代码层面强制保障不可变性的手段。如果不这么做,外部代码可能会不小心修改值对象的内部状态(比如直接往tags列表里加元素),破坏值对象的语义一致性——毕竟值对象的相等性是基于所有属性值的,一旦内部状态被偷偷修改,会导致各种难以追踪的bug。

给你举个实际的代码例子(Java):

public class Product {
    // 用final保证字段不能被重新赋值
    private final List<String> tags;

    public Product(List<String> tags) {
        // 把传入的列表转成不可修改的,彻底杜绝外部修改
        this.tags = Collections.unmodifiableList(new ArrayList<>(tags));
    }

    // 提供生成新实例的方法,来实现"更新"语义
    public Product addTag(String newTag) {
        List<String> newTagsList = new ArrayList<>(this.tags);
        newTagsList.add(newTag);
        return new Product(newTagsList);
    }

    // 只暴露只读的获取方法,不提供修改入口
    public List<String> getTags() {
        return tags;
    }
}

这种方式既遵守了值对象不可变的原则,又满足了更新标签的业务需求。因为新生成的Product和原来的是两个不同的值对象,对应不同的业务状态,完全符合值对象的设计理念。

总结一下:值对象的本质是值语义,不是不能更新状态,而是更新必须通过创建新实例来完成,绝对不能修改原有实例的任何属性。把字段设为final、集合设为不可修改,就是为了从根源上防止违反这个原则的操作。

内容的提问来源于stack exchange,提问作者Levi Tang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 05:58:17