领域驱动设计(Domain Driven Design)一下简称DDD
DDD是为了创造一个可测试的,可伸缩的,组织良好的软件模型。
一,采用DDD的原因:
- 表达准确的业务规则,不单单是包容产品设计(领域专家)和开发者,而是将其组成一个密切合作的团队。
- 准确的传达业务规则表现在完美实现设计的业务
- 帮助业务人员提高,DDD中每个人都在学习
- 知识集中可以将知识分享出去,不是仅被某些人掌握
- 开发和设计之间不存在翻译,而是使用相同的“语言”沟通
- 设计就是代码,代码就是设计,编码设计来自多次试验。
- DDD设计有战略和战术两种方式,战略设计帮助理解哪些投入是必要的,哪些是可以重用的,需要哪些人参与。战术设计帮助创建模型中是各个部件。
二,DDD主要关注三个方面:
- 将开发和产品设计聚集在一起,可以反映出产品是设计思维模型
- 关注业务战略,包含战略和战术设计。从而实现面向服务架构和业务驱动架构
- 通过建模工具,将领域设计转换成软件,同时设计出的软件可测试,具有良好的伸缩性,允许分布式计算
未经过DDD,导致出现大量的贫血对象
贫血对象:在领域中,有些对象几乎没有业务操作,并且Getter 和Setter大部分是为了映射数据库里的领域模型。
- 主要是些公有的getter和setter方法, 并且几乎没有 业务逻辑,或者甚至完全没有业务逻辑——对象嘛,主要就是用来容纳屈 性值的?
- 软件组件经常使用的领域对象是否包含了系统主要的业务逻辑,并且多数 情况下你需要调用那些getter和setter? 你可能会将这样的客户代码称为服务层(Service Layer)或者应用层(Application Layer) (4, 14)代码。
——摘自《领域驱动设计》
大段大段的setter方法让人崩溃
customer.setCustomerFirstName(customerFirstName);
customer.setCustomerLastName(customerLastName);
customer.setStreetAddressl(streetAddressl);
customer.setStreetAddress2(streetAddress2);
customer.setCity(city);
customer.setStateOrProvince(stateOrProvince);
customer.setPostalCode(postalCode);
customer.setCountry(country);
customer.setHomePhone(homePhone);
customer.setMobilePhone(mobilePhone);
customer.setPrimaryEmailAddress(primaryEmailAddress);
customer.setSecondaryEmailAddress (secondaryEmailAddress);
如果这时候有一个保存方法
saveCustomer(customer);
咋一看,是保存客户信息。但是在领域中,你不知道业务是何时使用这个方法的,即无法映射实际的业务场景。
然后过一段时间,customer的属性发生了变化,添加了一两个属性,并且属性的参数需要符合一定的要求,就会出现下列代码:
if (customer == null) {
customer = new Customer();
customer.setCustomerid(customerid);
}
if (customerFirstName 1= null) {
customer.setCustomerFirstName(customerFirstName);
}
if (customerLastName ! = null) {
customer.setCustomerLastName(customerLastName);
}
...
...
...
这种代码已经表示数据-映射开始变糟了。你已经不清楚什么时候参数是必须的,该不该保存customer。
而且随着时间的流逝,方法变化的来龙去脉越来越模糊,弄清楚需要花费大量的时间。
三,DDD 的《通用语言》
通用语言是用来交流领域中(业务),行业专家和程序编写者沟通交流的语言,既不是行业专家使用的专业术语,也不是专门的业务语言。通用语言主要是方便团队中的行业专家以及开发人员沟通,比如,模型图,领域文档等(包含领域中术语与术语含义的解释,通常有个表格)
按照通用语言的业务划分,不应该出现贫血对象,那么上述代码在DDD的指导下会变成:
public interface Customer {
void changePersonalName( String firstName, String lastName);
void postalAddress(PostalAddress postalAddress);
void relocateTo(PostalAddress changedPostalAddress);
void changeHomeTelephone(Telephone telephone);
void disconnectHomeTelephone();
void changeMobileTelephone(Telephone telephone);
void disconnectMobileTelephone ();
void primaryEmailAddress(EmailAddress emailAddress);
void secondaryEmailAddress(EmailAddress emailAddress);
}
这样,业务就会体现在接口中,而方法对应的应用层也会随之变化:
@Transactional
public void changeCustomerPersonalName( String customerld, String customerFirstName, String customerLastName) {
Customer customer = customerRepository.customerOfId(customerid);
if (customer == null) {
throw new IllegalstateException("Customer does not exist");
}
customer.changePersonalName(customerFirstName, customerLastName);
}
你会说,这个方法太单一了。没错,在DDD中,参照模型对数据修改,不需要使用一个方法,然后后面跟上一大堆null去判断了。
通用语言不是万能的,而是在领域中普遍的,表达清楚的;一般会有领域界限上下文限定,如果想映射到其他领域中,大部分情况会失败
作为开发者,我们都是技术思想者,技术实现对于我们来说并不是什么难事。我并不是说技术地思考不好,只是说有时少从技术层面去思考会更好。这么多年来,我们都习惯了单从技术层面完成软件开发,那么现在,是时候考虑一种新的思考方式了。为你的业务领域开发一门通用语言是一个好的出发点。
一 一 实现领域驱动设计
网友评论