聚合根中子实体的目的是什么? [英] What is the purpose of child entity in Aggregate root?

查看:81
本文介绍了聚合根中子实体的目的是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[跟踪此问题&评论:实体应具有方法,如果可以的话,如何防止将其称为外部聚合]



如标题所示:尚不清楚实体作为一个子实体的实际/精确目的是什么?



根据我在许多地方读到的内容,这些是属于聚合子项的实体:


  1. 它具有本地要聚合的身份

  2. 直接访问,但只能通过聚合根访问

  3. 它应具有方法

  4. 不应从聚合中获取

在我看来,这转化为几个问题:


  1. 实体应为私有聚合

  2. 我们需要只读副本Value-Object来公开信息f rom实体(例如,至少为了使存储库能够读取它以便保存到db)

  3. 我们在实体上拥有的方法在Aggregate上重复了(或反之,反之亦然,我们必须在Aggregate上具有处理实体的方法在实体上重复)

所以,为什么我们要拥有一个实体而不是仅值对象?似乎只有一个值对象,所有方法都合计并公开值对象(我们已经在复制实体信息)了,这更加方便。



PS。
我想将重点放在子实体上,而不是实体集合上。






[回应中的更新以 Constantin Galbenu 回答&注释]



那么,实际上,您会有类似的东西吗?

  public class Aggregate {
...
private _someNestedEntity;

public SomeNestedEntityImmutableState EntityState {
get {
返回this._someNestedEntity.getState();
}
}

public ChangeSomethingOnNestedEntity(params){
this._someNestedEntity.someCommandMethod(params);
}
}


解决方案



  1. 实体应该是私有的,以进行聚合


是。而且我认为这不是问题。继续阅读以了解原因。



  1. 我们需要只读复制Value-Object到公开来自实体的信息(例如,至少是为了使存储库能够读取信息以便将
    保存到数据库)




否。使您的聚合返回在聚合的每种方法上都需要保留的和/或在事件中引发的数据。



原始示例。现实世界将需要更细粒度的响应,也许 performMove 函数需要使用 game.performMove 的输出来构建适当的结构对于持久性和eventPublisher:

  public void performMove(String gameId,String playerId,Move move){
游戏= this.gameRepository.load(gameId); //游戏是AR
List< event>事件= game.performMove(playerId,move); //执行
persistence.apply(events)//事件包含实体的ID,因此持久性能够应用事件并保存ID所使用的更改,并且更改后的数据也包含在事件中。
this.eventPublisher.publish(events); //通知系统其余部分发生了某些情况
}

内部实体。让实体重新调整已更改的数据,因为其方法调用(包括其ID)会在AR中捕获此数据,并为持久性和eventPublisher构建适当的输出。这样,您甚至不需要将具有实体ID的公共只读属性公开给AR,并且AR既不向应用程序服务公开其内部数据。这是摆脱Getter / Setters包对象的方法。



  1. 我们在实体上拥有的实体在Aggregate上重复(反之亦然,我们必须在Aggregate上处理实体
    的方法在实体上重复)


有时,要检查和应用的业务规则仅属于一个实体,其内部状态和AR只是网关。可以,但是如果您发现此模式太多,则表明存在错误的AR设计。也许内部实体应该是AR,而不是内部实体,也许您需要将AR拆分为服务器AR(并且其中一个是旧的ner实体),等等。。。或两种方法。



响应dee zg的评论:


做什么persistance.apply(events)到底能做什么?它只保存整个
个聚合还是仅保存一个实体?


都不行。集合和实体是领域概念,而不是持久性概念;它们是域概念。您可以拥有不需要与域概念一对一匹配的文档存储,列存储,关系存储等。您不会从持久性中读取聚合和实体;您可以使用从持久性读取的数据在内存中构建聚合和实体。聚合本身不需要保留,这只是可能的实现细节。请记住,聚合只是组织业务规则的一种结构,并不是要表示状态。



您的事件具有上下文(用户意图)和数据更改(以及需要ID来识别持久性中的事物),因此在知道以下内容的持久性层中编写 apply 函数非常容易,这非常简单如果是关系数据库,执行什么操作以应用事件并保留更改。


请提供以下示例,为什么?是否最好(甚至不可避免地使用
?)使用子实体代替
以其ID作为值对象引用的单独AR?


为什么要用类和行为设计和建模类?



要抽象,封装,重用等。基本的 SOLID 设计。如果实体具有确保操作所需的域规则和不变性所需的一切,则该实体就是该操作的AR。如果您需要实体无法完成的额外的域规则检查(即实体没有足够的内部状态来完成检查或自然不适合实体及其代表),则必须重新设计;有时可能是对进行额外域规则检查并将其他域规则检查委托给内部实体的聚合建模,有时可能是更改实体以包括新事物。它太依赖域上下文,所以我不能说有一个固定的重新设计策略。



请记住,不要在代码中对聚合和实体建模。您仅对具有行为的类进行建模以检查域规则以及进行检查和响应更改所需要的状态。这些类可以充当不同操作的集合或实体。这些术语仅用于帮助交流和理解类在每个操作上下文中的作用。当然,您可能会遇到该操作不适合实体的情况,并且可以使用V.O建模聚合。持久性ID,它是可以的(不幸的是,在DDD中,默认情况下几乎不知道所有上下文都可以)。



您是否想从解释事情的人那里得到更多启发比我好多了? (不是讲英语的人是解决这些复杂问题的障碍)



https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1
http://blog.sapiensworks .com / post / 2016/07/14 / DDD-Aggregate-Decoded-2
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3


[ Follow up from this question & comments: Should entity have methods and if so how to prevent them from being called outside aggregate ]

As the title says: i am not clear about what is the actual/precise purpose of entity as a child in aggregate?

According to what i've read on many places, these are the properties of entity that is a child of aggregate:

  1. It has identity local to aggregate
  2. It cannot be accessed directly but through aggregate root only
  3. It should have methods
  4. It should not be exposed from aggregate

In my mind, that translates to several problems:

  1. Entity should be private to aggregate
  2. We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)
  3. Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)

So, why do we have an entity at all instead of Value Objects only? It seams much more convenient to have only value objects, all methods on aggregate and expose value objects (which we already do copying entity infos).

PS. I would like to focus to child entity on aggregate, not collections of entities.


[UPDATE in response to Constantin Galbenu answer & comments]

So, effectively, you would have something like this?

public class Aggregate {
    ...
    private _someNestedEntity;

    public SomeNestedEntityImmutableState EntityState {
       get {
          return this._someNestedEntity.getState();
       }
    }

    public ChangeSomethingOnNestedEntity(params) {
       this._someNestedEntity.someCommandMethod(params);
    }
}

解决方案

  1. Entity should be private to aggregate

Yes. And I do not think it is a problem. Continue reading to understand why.

  1. We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)

No. Make your aggregates return the data that needs to be persisted and/or need to be raised in a event on every method of the aggregate.

Raw example. Real world would need more finegrained response and maybe performMove function need to use the output of game.performMove to build propper structures for persistence and eventPublisher:

  public void performMove(String gameId, String playerId, Move move) {
    Game game = this.gameRepository.load(gameId); //Game is the AR
    List<event> events = game.performMove(playerId, move); //Do something
    persistence.apply(events) //events contains ID's of entities so the persistence is able to apply the event and save changes usign the ID's and changed data wich comes in the event too.
    this.eventPublisher.publish(events); //notify that something happens to the rest of the system
  }

Do the same with inner entities. Let the entity retun the data that changed because its method call, including its ID, capture this data in the AR and build propper output for persistence and eventPublisher. This way you do not need even to expose public readonly property with entity ID to the AR and the AR neither about its internal data to the application service. This is the way to get rid of Getter/Setters bag objects.

  1. Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)

Sometimes the business rules, to check and apply, belongs exclusively to one entity and its internal state and AR just act as gateway. It is Ok but if you find this patter too much then it is a sign about wrong AR design. Maybe the inner entity should be the AR instead a inner entity, maybe you need to split the AR into serveral AR's (inand one the them is the old ner entity), etc... Do not be affraid about having classes that just have one or two methods.

In response of dee zg comments:

What does persistance.apply(events) precisely do? does it save whole aggregate or entities only?

Neither. Aggregates and entities are domain concepts, not persistence concepts; you can have document store, column store, relational, etc that does not need to match 1 to 1 your domain concepts. You do not read Aggregates and entities from persitence; you build aggregates and entities in memory with data readed from persistence. The aggregate itself does not need to be persisted, this is just a possible implementation detail. Remember that the aggregate is just a construct to organize business rules, it's not a meant to be a representation of state.

Your events have context (user intents) and the data that have been changed (along with the ID's needed to identify things in persistence) so it is incredible easy to write an apply function in the persistence layer that knows, i.e. what sql instruction in case of relational DB, what to execute in order to apply the event and persist the changes.

Could you please provide example when&why its better (or even inevitable?) to use child entity instead of separate AR referenced by its Id as value object?

Why do you design and model a class with sate and behaviour?

To abstract, encapsulate, reuse, etc. Basic SOLID design. If the entity has everything needed to ensure domain rules and invariants for a operation then the entity is the AR for that operation. If you need extra domain rules checkings that can not be done by the entity (i.e. the entity does not have enough inner state to accomplish the check or does not naturaly fit into the entity and what represents) then you have to redesign; some times could be to model an aggregate that does the extra domain rules checkings and delegate the other domain rules checking to the inner entity, some times could be change the entity to include the new things. It is too domain context dependant so I can not say that there is a fixed redesign strategy.

Keep in mind that you do not model aggregates and entities in your code. You model just classes with behaviour to check domain rules and the state needed to do that checkings and response whith the changes. Theese classes can act as aggregates or entities for different operations. Theese terms are used just to help to comunicate and understand the role of the class on each operation context. Of course, you can be in the situation that the operation does not fit into a entity and you could model an aggregate with a V.O. persistence ID and it is OK (sadly, in DDD, without knowing domain context almost everything is OK by default).

Do you wanna some more enlightment from someone that explains things much better than me? (not being native english speaker is a handicap for theese complex issues) Take a look here:

https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1 http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2 http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3

这篇关于聚合根中子实体的目的是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆