对领域事件驱动的一些知识的梳理(以下内容是从内到外进行梳理)
值对象:一个没有标识符的对象。
值对象通常不会被修改,而是通过创建新的值对象来表示不同的状态。
没有自己的生命周期,它们随着所属的实体或聚合根的生命周期而存在。它们更多地用于描述和表示数据,而不是行为。
订单作为聚合根,而其中的一些属性可以被抽象为值对象。例如,收货人信息可以被封装成一个值对象。
public class ShippingAddress {
private String street;
private String city;
private String state;
private String postalCode;
}
通过使用值对象ShippingAddress,我们可以将收货人信息与订单关联起来,同时减少代码的冗余和复杂性。
public class Order {
private String orderNumber;
private LocalDateTime orderDate;
private BigDecimal orderAmount;
private ShippingAddress shippingAddress;
}
实体:
实体应该是富有业务行为且具有唯一标识符的对象。在不同的设计阶段实体是可以改变的,但是根据唯一标识符始终能定位到这个唯一对象。
贫血模型
贫血模型是指领域对象里只有get和set方法(POJO),所有的业务逻辑都不包含在内而是放在Business Logic层。
充血模型
充血模型是指数据和对应的业务逻辑被封装到同一个类中。因此,这种充血模型满足面向对象的封装特性,是典型的面向对象编程风格。
引入新的问题
什么样的逻辑应该放在Domain Object中,什么样的业务逻辑应该放在Business Logic中?
Rod Johnson提出原则是“case by case”,可重用度高的,和domain object状态密切关联的放在Domain Object中,可重用度低的,和domain object状态没有密切关联的放在Business Logic中。
把一个logic放到domain object中以后,这个domain object应该仍然独立于持久层框架之外,这个domain object仍然可以脱离持久层框架进行单元测试,这个domain object仍然是一个完备的,自包含的,不依赖于外部环境的领域对象,这种情况下,这个logic才是domain logic。
public class Order {
private String orderNumber;
private LocalDateTime orderDate;
private BigDecimal orderAmount;
private ShippingAddress shippingAddress;
// 封装业务行为
public void cancelOrder() {
// 执行取消订单的逻辑
}
public void updateShippingAddress(ShippingAddress newAddress) {
// 执行更新收货地址的逻辑
}
}