柔性设计
Intention Revealing Interfaces
描述类和方法时,要让其可以自己揭示它们的效果和目的.
这个很好理解, 让接口具有自我描述性,不要让使用方通过看实现来了解接口的使用方法.
Side-Effect-Free Function
我们先定义2个概念:
- 函数: 不产生副作用的操作, 返回值代表了它的产出.可以被调用多次,每次都返回相同的值.
- 命令: 会产生副作用, 会导致对象状态变更.
应该怎么应用?
首先,使用函数,就没有副作用. 其次,把一些复杂的逻辑放到ValueObject中,而对状态的改变,既对entity中属性的改变,尽量做得比较直接,不要把在entity的方法中放入大量的逻辑.
该有的复杂逻辑是少不了额,我们只是把它们放到sid-effect-free的函数中.这种'后置条件'
Assertions
实体中总会遗留一些有副作用的命令, 在这种情况下,使用断言(assertion)来明确的把副作用表示出来.
如果编程语言不支持assertion,就把它编写成单元测试.
Conceptual Contours
直接翻译过来就是概念轮廓.这是个关于拆分粒度的权衡.
如果把所有的元素放到一个大的整体里面, 大量的概念被混在一起, 就会变得很难理解.
如果拆分的太细, 会迫使客户理解各部分是怎样组合的, 更糟的是有些概念会丢失, 比方说在一个细的粒度下,我们能看到车胎和车座,但是无法看到自行车这个整体.
首先我们要认可领域是可以被建模的, 有一个概念上的轮廓.
就像素描一样,现实中的实物,就是我们的概念轮廓, 我们会不断的修改, 以达到和实物逼近的画面. 概念轮廓(conceptual contours)的得来,也是这样一个过程, 我们在不断的重构, 使我们的模型不断的逼近领域. 当连续的重构只是做出的一些局部修改的时候, 这就是模型与领域相吻合的信号. 如果遇到一个需求, 需要大幅的修改模型才能满足, 这说明模型和领域之间还有很大差距, 我们对领域的理解也有偏差.
Standalone Class
互相依赖使得模型和设计变得难以理解和维护.
类的成员变量是依赖, 方法的参数和返回值也是依赖. 如果要尝试去搞懂一个类, 它的所有依赖也要被牵扯进来.
Module的目的是为了限制依赖, 当我们识别出一个高度内聚的子领域, 并把它放入一个module中, 它也随之与系统的其他部分解除了联系.
但是Module内部也存在依赖. 如何去除依赖? 我们应该对每个依赖提出质疑, 直到证实它确实表示这个对象的基本概念. 我们把所有的无关概念提取到对象之外的时候, 类就变成了完全孤立的了, 使得我们可以单独的研究和理解它.
低耦合是减少概念过载的基本方法, 孤立的类(standalone class)是低耦合的极致.
Closure of Operations
什么是闭合(closure)?
closure这个概念来源于数学. 简单来说就是某种运算,如果只在某个概念集合内进行, 就是闭合的,比方说加法运算就是实数集中的闭合运算.
闭合的好处?
闭合的操作极大的简化了对操作的理解,同时,闭合操作的链接或组合也很容易理解.
怎么做?
- 让参数和返回值相同,这个函数就是闭合的.
- 如果函数是类方法, 并且用到了类中的状态, 则参数和返回值都应该是这个类.
Declarative Design
Angles of Attack
切入问题的角度, 既具体实施时的一些技巧.
- 分割子领域
- 尽可能利用已有的领域模型, 其中有些已经被精华和提炼好久 .例如支付领域.
参考:
领域驱动设计:软件核心复杂性应对之道