如何让我们设计的框架,在后期更容易维护和修改,本章给出来了一些参考思路。
第十章 柔性设计
为了使项目能够跟随着开发工作的进行加速前进,而不会由于它自己的老化停滞不前,设计必须要让人们乐于使用,而且易于做出修改。这就是柔性设计。
开发人员扮演着两个角色,设计出的技术框架必须为为这两个角色服务:
- 将领域对象组织成应用程序代码,即可落地
- 设计对修改代码的开发人员友好,即易修改
做出这样的设计,没有具体的公式,但是有一些原则可供参考,咱们一一进行介绍。
10.1 INTENTION-REVEALING INTERAFCES
上边三个单词字面意思分别是意图 解释 接口,书上的翻译是“释意接口”。名称看着很高大上,其实意思很简单,就是“我们在定义变量、方法名称、类名称时,要描述它们的效果和目的,做到见闻知意”。只表明最终效果,无需表露内部的实现细节"。
10.2 SIDE-EFFECT-FREE FUNCTION
SIDE-EFFECT-FREE 是无副作用的意思,题目整体翻译成”无副作用方法“。这里先解释两个概念:副作用和函数。
副作用:”副作用“暗示”意外的结果“。任何对系统状态产生的影响都叫副作用。
函数:返回结果而不产生副作用的操作称为函数。这个概念有点绕,和数学上对函数的定义有所不同。
我们可以宽泛地把操作分为两个大的类别:命令和查询。查询是从系统获取信息,只是简单地访问数据。命令是修改系统的操作。可见,命令是容易引起副作用的。为了使命令引起的副作用最小化,有两个方法:
- 把命令和查询严格的放在不同的操作中,把副作用隔离到最小的范围;
- 做一些替代性的设计,比如把对ENTITY的操作,转化为对VALUE OBJECT的操作。
比如书中提到的一个例子,有个颜料类paint。paint有两个属性:颜色和体积。颜料掺和在一起,会变色。显然paint是个ENTITY。两个paint直接进行掺的话,两个paint的属性都会发生变化。为了计算两个颜料掺在一起后,会变成什么颜色,设置了一个VALUE OBJECT类型的类 paint color。这样paint color1与paint color2掺在一起,直接形成了paint color3。paint color3只是个颜色的值而已,不影响paint1和paint2。而且paint color类中还内聚了颜色掺在一起的变色规则,领域分工更加明确。用类似的方法,可以在一定程度上控制副作用。
10.3 ASSERTION
把复杂的计算封装到SIDE-EFFECT-FREE FUNCTION中可以简化问题,但实体仍然会留有一些有副作用的命令。使用这些ENTITY的人必须了解使用这些命令的后果。在这种情况下,使用ASSERTION(断言)可以把副作用明确的地表达出来,使它们更易于处理。
“断言”是软件行业的术语,表面的意思是“断定的说”,具体意思是“软件的运行结果是可以预测的”。
采用断言的作用一是可以便于测试;二是可以便于开发人员更清晰理解操作的后果。
例如asssertEquals(2.5,getVolume());用于判断的getVolume()结果是不是2.5。
10.4 CONCEPTUAL CONTOUR
CONCEPTUAL CONTOUR(概念轮廓)这部分,作者讲的比较抽象。我总结了下。基本原则是我们不要把框架分的太细,也不要分的太粗。
- 不要太细是指能合并的,就合并起来。比如转账业务。扣款和打款是一个整体。就要整体来考虑。有时候,在实现上,技术人员对一些细节无需关系,这时候也不能分的太细。比如颜料混合的方法。只需要给出最终颜料的样子,不需要给出具体的颜料混合的具体参数变化。
- 不能太粗,是说我们要对功能进行更细的分解,以便灵活地组合它们。
还是要在不断的重构中,逐渐形成概念轮廓。这个没有最终形态,只有不断演进。
10.5 STANDALONE CLASS
尽力把最复杂的计算提取到STANDALONE CLASS(独立的类)中,实现此目的的一种方法是从存在大量依赖的类中,将依赖移植到VALUE OBJECT。这个模式和上个模式都是在遵循“高内聚、低耦合”的理念。按作者的话说,独立的类是低耦合的极致。
10.6 CLOSURE OF OPERATION
CLOSURE翻译为“ 闭合 ”,OPERATION翻译为“操作”,这个模式的翻译过来叫闭合操作。举个例子带大家了解下这个概念。
两个实数相乘,结果仍为实数。由于这一点永远成立,乘法运算的结果永远无法脱离实数这个集合,因此我们说实数的“乘法运算是闭合的”。当我们对集合中的任意两个元素组合时,结果仍在这个集合中,这就叫做闭合操作。
在适当的情况下,在定义操作时让他的返回类型与其参数的类型相同。如果实现者的状态在计算中会被用到,那么实现者实际上就是操作的一个参数,因此参数的返回值应该与实现者有相同的类型。这样的操作就是在该类型集合中的闭合操作。这种模式常用于对VALUE OBJECT的操作。
有时候,我们会遇到“半个闭合操作”的情况。当没有形成闭合操作的那个多出来的类型是基本类型或基础库类时,它几乎与CLOSURE OF OPERATION一样。这种半闭合操作,也是可以接受的。
10.7声明式设计
声明式设计是在程序中定义一种模式或者规则。开发者按照这种成型的规则编写自己的代码。声明式设计最大的价值是用一个非常窄的框架来自动处理某个特别单调且容易出错的方面,如持久化和对象关系映射。最好的声明式设计能够使开发人员不必去做那些单调乏味的工作,同时又不限制他们的设计自由。
作者在书中又举了那个化学品的例子。例子中用程序实现逻辑运算(OR AND NOT)。我更加感觉到要想编写好代码,一定要有扎实的数学功底。比如上述的逻辑运算,实际就是离散数学中的内容。作者也在书中提到,一定要复用一些成熟的数据逻辑。将一些复杂的业务概念用数学概念提炼出来。专门的数学很整齐,可以通过清晰的规则进行组合,并很容易理解。
声明式设计的高阶形态是建立一种“领域特定语言”来描述这种设计。然后框架自动解析这种语言。
柔性设计可以极大地提升软件处理变更和复杂的能力。第15章讲讨论柔性设计的战略价值,我们将把它作为一种工具,用来精炼领域模型,以便使大型和复杂的项目易于掌握。