当前位置: 首页 > 知识库问答 >
问题:

没有业务属性的集合或实体

令狐翰
2023-03-14

关于以下摘录,关于CQR和ddd,摘自Nick Tune,Scott Millett的领域驱动设计的模式、原则和实践

这是否意味着命令端的域模型可以省略大部分业务属性?对于例如客户实体,它会是什么样子?

客户实体能否省略名字、姓氏等?如果是这样,这些业务属性会在哪里?仅在CustomerEntity的读取模式中?

或者,除了包含所有业务属性的CustomerEntity之外,可能还会有CustomerAggregate以1:1关系包装CustomerEntity,并且命令对象会对CustomerAggregate进行操作?(我觉得很奇怪)。

“客户实体不合理”是什么意思?

共有2个答案

冯育
2023-03-14

如果您使用的是事件源,那么确实可以在不添加实现业务逻辑所不需要的属性的情况下对聚合进行建模。

下面是一个例子:

class Customer {

    public Guid ID { get; private set; }

    public Customer(Guid id, firstName, lastName, ...) {

        ID = id;

        this.AddEvent(new CustomerCreatedEvent(id, firstName, ....);
    }

    public void ChangeName(firstName, lastName) {
       this.AddEvent(new CustomerRenamedEvent(this.ID, firstName, lastName), 
    }
}

Custom只有ID属性,因为它需要将其添加到它生成的每个事件中。FirstName和LastName被省略,因为即使在调用ChangeName方法时也不需要它们。它只记录了发生这种情况的事件。如果您的逻辑需要名字,那么您可以添加它。您可以省略任何不需要的属性。

在这种情况下,您的存储库将只保存事件,而不关心客户属性的值。

在阅读端,在向用户显示这些属性时,您可能需要这些属性。

如果您的聚合不是事件源的,那么您可能需要聚合上的更多属性来实现它的逻辑,并且它们将被保存到数据库中。

下面是一个例子:

class Customer {

    public Guid ID { get; private set; }
    public string FirstName { get; private set; }
    public string LastName { get; private set; }

    public void ChangeName(firstName, lastName) {
       FirstName = firstName;
       LastName = lastName;
    }
}

在这种情况下,存储库将需要这些属性,因为它将生成一个查询,用新值更新数据库

不确定“客户实体没有意义”是什么意思。

齐才艺
2023-03-14

您指出的文本意味着您不必为整个系统甚至整个有界上下文建模一个可重用的实体(不要为可重用的真实事物建模)。这样做是个糟糕的设计。

您必须对执行操作的Aggregate进行建模。您仅向Aggregate提供执行该操作所需的数据,并且聚合响应,即域所遭受的更改,是您必须坚持的。

为什么是实体和副总裁?

为了对一致性进行建模,封装和解耦是基本部分,但这些是实现细节。对于DDD,重要的是不同的角色(或概念)。

当提供聚合(构造函数、函数调用参数等)时,聚合必须知道它是否正在与实体和/或V. O.一起工作以构建其响应。

如果域操作意味着实体属性(在整个系统中具有唯一标识的东西)的更改,那么聚合的响应(一旦检查了所有规则和不变量)应该包括新的属性值和允许持久化更改的实体标识。

因此,默认情况下,每个聚合都有自己的实体,具有聚合操作所需的唯一标识和属性。

一个聚合可以有一个具有ID及其名称的客户实体。另一个聚合可以有一个具有ID及其Karma点的客户实体。

因此,每个聚合都有自己的内部客户实体可供使用。当你输入一个聚合时,你会传递客户数据(即ID和姓名或ID和业力点),聚合将该信息视为一个实体(如果聚合内部有一个结构、类等来表示实体,这是一个实现细节问题)。

一件重要的事情是:如果你只需要处理实体ID,那么就把它当作一个V.O.(CustomerIdentityVO),因为ID是不可变的,在这个操作中,你可能只需要在持久性中的某个字段中写入这个CustomerIdentityVO,而不需要更改任何Customer属性。

这是标准的愿景。一旦你开始识别与几个聚合相关的公共结构,或者一个聚合可以使用相同的数据执行多个操作,你就开始重构、重用等等。这只是一个好的OOP设计和坚实的原则问题。

请注意,我试图高高在上的实施细节。我知道,你几乎总是会有不想要的工件,这取决于编程范式类型、选择的编程语言等。但是这种方法可以帮助你避免更糟糕的工件。

推荐阅读资料:

http://blog.sapiensworks.com/post/2016/07/29/DDD-Entities-Value-Objects-Explainedhttp://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3

https://blog.sapiensworks.com/post/2016/08/19/DDD-Application-Services-Explained

对于一个完整的拼图视觉。

 类似资料:
  • 问题内容: 我是第一次使用Django,并且正在尝试构建API,我正在遵循一些教程和示例,并且可以正常使用,但是在安装所有要求和项目后,现在我正在Raspberry Pi中运行该项目。因以下错误而失败: 我的views.py具有以下代码: 我真的不知道为什么可以在笔记本电脑上工作,但不能在Raspberry Pi上工作。 这是否发生在某人或任何人都知道为什么会发生这种情况? 非常感谢! 编辑: 这

  • 我正在用Laravel 5.2开发一个Web应用程序,但有一个问题我无法解决。 我有一个扩展了雄辩模型的模型,但当我试图输出带有“where”的数据库表时,例如 它返回一个包含许多信息的集合,这些信息此时对我来说无用,比如“守卫”、“键入”...我的表的数据在“属性”下。遵循laravel的指南,我看到每个人都像我一样简单地使用它,然后用

  • 我在两个实体之间有双向或父/子关系: 我要选择没有的所有或的属性设置为的。 我使用的是。

  • 我有以下内容: 我想忽略在RegimenEntity中设置的regimenDrugs内的所有RegimenDrugEntity对象的id。 此映射(target=“regimenDrugs.id”,ignore=true)不编译。

  • 我有个问题。我有以下几门课: 那么我还有下面的数组: 现在,在我的代码中有一个for循环,它在列表中循环,如下所示: 但是我需要在循环中更新我当前所在的类的属性。如何按语法构建函数?

  • 假设我有以下映射目标。 如何从其他属性的Iterable映射到其他属性? 我可以这样做吗?