当前位置: 首页 > 编程学习 > 软件工程 > 领域驱动 > 正文

从零开始使用CodeArt实践最佳领域驱动开发(三)

2018-04-22 来源:博客园/一个人抽烟

5.领域模型设计

在开始考虑如何构建账户子系统的领域模型之前,我们先来看看关于CA里领域模型的基本概念。初次接触这些陌生的概念确实会一知半解,不过没有关系,大家实践几次领域设计后就会融会贯通,深刻体会到这些概念背后隐藏的优点。

概念1:领域对象。领域模型里的一切对象都应该是领域对象所谓的领域对象就是指遵守领域规则的对象,这是它与普通对象最大的区别。领域规则主要由以下几点组成:

1) 领域对象永远都不会为null。在详细说明这一点之前,大家一定要知道这个规则跟数据库里的字段不能为null没有任何关系。到目前为止,我们都没有提到如何使用数据库技术,这个教程之后的内容也不会讲述与数据库有关的话题,因为这些都与领域模型的建立没有一丁点的关系,没有数据库一样可以成功建立领域模型。各位一定要摒弃以前根深蒂固的开发思路,放空自己的思想,重新接收领域模型里的概念。

言归正传,在领域的世界里,一切对象都是有其存在的意义的。什么叫存在的意义?这体现在职责上,一个对象可以履行某项职责那么这个对象就是有意义的存在。在领域世界里绝对不会出现不具备任何职责的对象。大多数情况下,对象需要提供方法以便其履行职责(.Net里的属性也是方法,只是被包装了而已)。

每年企业都会向政府交纳一定的税收,这是企业的职责之一,所以领域世界里的企业模型会有一个计算纳税金额的方法,该方法会根据企业的盈利计算出交税的金额。如果我问你,你创办的公司今年要交多少税?你可以通过该方法计算结果,告诉我需要交纳10万元。那么,你没有公司呢?你根本就没有自己创办的公司,那你要如何回答我这个问题?回答“很抱歉,我没有公司”吗?错,程序的世界是理性的世界,一切都是严谨的,计算纳税金额的方法定义返回值是浮点数,那么这个方法在任何情况下都应该返回一个浮点数(抛出异常例外)。当我问你的公司要交纳多少税,你只能告诉我具体的数值,我不管你是否有自己的公司,那是你自己要考虑的事情。所以,你应该回答“0”。

分析到这里,大家发现一个问题没有,一个没有创办公司的人却也可以知道“自己创办的公司”今年要交纳多少税收,只不过由于他实际上没有公司,所以计算的结果为0。因此,判定事物能否履行某项职责和这个事物的实例是否存在没有必然的联系。我们只要设计了名称为Corp的企业领域模型,在Corp类里定义了方法CalculateTax(计算税收),那么在任何情况下,Corp的实例都应该可以成功的调用该方法,至于计算的结果由Corp内部去处理,外界不用考虑这些细节。所以,即使不存在编号为135的Corp对象,我们依然可以根据编号135找到一个为Empty的Corp对象,调用该对象的CalculateTax方法会计算并得到税收值为0的结果。

所以,在领域的世界里,我们规定对象可以为Empty但是永远不能为null,因为null表示不存在,不存在的对象无法履行任何职责。我们衡量对象是否存在的唯一依据就是职责,一个没有职责的对象根本就不会被设计出来,所以领域世界里没有不存在的对象,而Empty则表示对象是存在的,只不过数据都是空的,空对象依然可以履行职责,只是履行职责的结果会和非空对象执行的结果有所不同。大家千万不要小看“领域对象永远都不会为null”这项特性,它可以解决很多问题。比如说:传统开发中删除一条数据必须级联删除多条数据的情况在CA的开发模式里几乎不存在、对象之间的硬关联也可以由这项特性解除。在以后的示例中我们会帮助各位进一步理解这个概念。下图是体现这一规则的INotNullObject接口定义:

2) 每个领域对象都具有验证固定规则的能力。固定规则与业务规则不同,这组规则不会随着使用对象的场景的变化而变化,它是对象自身固有的规则。例如人的年龄不可能有上万岁,汽车的轮胎个数也不会有上百个,这些都是领域模型里的固定规则,不会随着人或汽车这一事物在不同的使用场景里而发生规则的改变。CA通过实现ISupportFixedRules接口来完成领域对象验证固定规则的能力: