5 创建实体
新建一个实体时,我们总期望通过构造器就能初始化足够多的实体状态,因为这样更容易通过各种条件查找到该实体。
在使用及早生成唯一标识的策略时,构造器至少需接受唯一标识参数。若还有可能通过其他方式查找实体,比如名字或描述信息,那应该将这些参数一并传给构造器。
有时一个实体维护一或多个不变条件(Invariant,在整个实体生命周期中都必须保持事务一致性的一种状态) 。
不变条件主要是聚合所关注的,但聚合根也是实体。
如果实体的不变条件要求该实体所包含的对象都不能为null或必须由其他状态计算所得,那么这些状态也需作为参数传递给构造器。
public class User extends Entity { ... // 每一个User对象都必须包含tenantld、username, password和person属性。 // 即在User对象得到正确实例化后,这些属性不能为null // 由User对象的构造器和实例变量对应的setter方法保证这点 protected User (Tenantld aTenantld String aUsername, String aPassword, Person aPerson) ( this(); this.setPassword(aPassword); this.setPerson(aPerson); this.setTenantld(aTenantld); this.setUsername(aUsername); this.initialize(); } ... protected void setPassword(String aPassword) { if (aPassword == null) { throw new 11legalArgumentException( "The password may not be set to null."); ) this.password = aPassword; ) protected void setPerson(Person aPerson) ( if (aPerson == null) ( throw new IllegalArgumentException("The person may not be set to null."); } this.person = aPerson; } protected void setTenantld(Tenantld aTenantld) ( if (aTenantld == null) { throw new IllegalArgumentException("The tenantld may not be set to null."); } this.tenantld = aTenantld; } protected void setUsername(String aUsername) ( if (this.username != null) { throw new IIlegalStateException("The username may not be changed.n); } if (aUsername == null) { throw new IllegalArgumentException("The username may not be set to null."); } this.username = aUsername; }
User对象展示了一种自封装性。在构造器对实例变量赋值时,把操作委派给实例变量对应的setter方法,便保证了实例变量的自封装性。实例变量的自封装性使用setter方法来决定何时给实例变量赋值。
每个setter方法都“代表着实体”对所传进的参数做非null检查,这里的断言称为守卫(Guard)。setter方法的自封装性技术可能会变得非常复杂。所以对于复杂的创建实体场景,可使用工厂。
User对象的构造函数被声明为 protected。 Tenant实体即为User实体的工厂也是同一个模块中唯一能够访问User 构造器的类。这样一来,只有Tenant能够创建User实例。
public class Tenant extends Entity { // 该工厂简化对User的创建,同时保证了Tenantld在User和Person对象中的正确性 // 该工厂能够反映通用语言。 public User registerUser(String aUsername, String aPassword, Person aPerson) { aPerson.setTenantld(this.tenantld()); User user = new User(this.tenantld(), aUsername, aPassword, aPerson); return user; }
参考
https://tech.meituan.com/2017/12/22/ddd-in-practice.html
《实现领域驱动设计》
实体和值对象:从领域模型的基础单元看系统设计
https://blog.csdn.net/Taobaojishu/article/details/106152641