【发布时间】:2019-08-28 13:28:50
【问题描述】:
我正在学习 DDD,但遇到了一个我无法解决的问题。 假设我们有以下域:
public class Hotel : AggregateRoot {
public List<Room> Rooms { get; private set; }
}
public class Room : Entity {
public string Name { get; set; }
public int Number { get; set; }
}
现在我们要为 RoomReservations 建模。
public class RoomReservationRecord : Aggregate {
public string CustomerName { get; set; }
public Room Room { get; set; } // <- this is problem
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
}
清晰可见,2 个聚合包含(共享)单个实体。从业务角度来看是有道理的,但从 DDD 角度来看,看起来 2 个聚合共享同一个实体。
- 这种方法是否正确,还是违反了“实体可以成为单个聚合的一部分”规则?
- 或者有更好(明显的方式)来模拟这种需求?
【问题讨论】:
-
此类问题强烈表明您没有正确识别聚合根。这里的问题是:Hotel 真的是聚合根吗?或者 RoomReservationRecord 不应该是一个聚合?或者
Room根本就不是一个实体,只是一个值类型。聚合也可以引用其他聚合,但只能通过其标识符(即RoomId而不是引用聚合上的Room) -
我也有同样的想法,但后来我意识到没有酒店就没有房间。因此,恕我直言,腾出空间聚合本身感觉不对。作为 VO 的房间也感觉不对,因为在现实生活中房间是独立的实体。它们可以通过唯一的编号来识别,另一个相同的房间不是同一个房间。我也可以将房间设为一个集合,但除非我们引入 Parent 参考,否则房间将有没有酒店的风险......这是一个非常酷的想法 tbh
-
对,但是对于房间预订来说,重要的是房间号和酒店(如果有多个酒店),可以很好地表示为值类型。值类型由其值标识,因此酒店+房间号几乎可以唯一识别它。当您只需要与房间的关联时,您为什么认为您需要一个完整的房间实体来为您的
RoomReservationRecord聚合? -
因为 Room 是一个实体。在获取 RoomReservation 记录时,DDD 的重点是在其中包含一个 Room 对象,而不是它的 ID。它仍然可以使用 ID,但恕我直言,OOP 和 DDD 即将在内存中生成对象图。
-
在获取 RoomReservation 记录时,DDD 的重点是在其中有一个 Room 对象,这并不真正正确。聚合根的要点是充当事务边界,在聚合内是在单个事务中完成的。房间作为 RoomReservation 的实体是没有意义的,因为
Room可以在没有RoomReservation的情况下存在,所以让它成为RoomReservation的实体是完全错误的。如果没有Hotel,Room怎么会存在,所以这听起来更像是正确的聚合,以及为什么保留的 ID 更有意义。