A.1 设计得当的抽象应具备的特质

本节集中讨论在设计得当的抽象身上可以找到的一些特质。讨论中会用软件工程和程序设计领域作为参照来帮助理解,不过重点是如何拥有一份精心设计的抽象,协助你更轻松地构建出可重复利用的领域模型。随着讨论逐渐深入,你将理解并学会欣赏,抽象在设计一个复杂的领域模型中所扮演的中心角色。经过一系列提取抽象的练习,你将能够越来越熟练地从嘈杂的细节中提炼出模型的核心概念。为此,我们首先要讨论几种特质,正是它们把优秀的抽象设计和失败的抽象设计区别开来。

enter image description here本节用易于理解的语言,讨论设计得当的抽象所应具备的若干优良品性。我会一边讨论,一边列出代码片段来演示这些优良品性在具体实现中的不同侧面。讨论到某个侧面的时候,我会选取最能充分展现其特征的编程语言来作解释。虽然面向对象编程范式占据的篇幅最大,但也有不少例子用了函数式编程原则来实现。如果你对某些例子所用的语言不熟悉,也不用急着去翻书架。因为都是一些简单而且符合直觉的例子,不需要对具体语言有深入研究,也能顺利地理解其中的设计原则。万一需要了解某些语言特性,附录C到附录F已经为你准备好了。

每一个抽象都向其客户提供一个功能。为了完成其功能,抽象向外公开一套契约(也叫做接口)供客户使用。契约根据客户的性质可以有各种变化。契约背后都有对应的实现,而且通常以抽象化手段把实现对客户隐藏起来,客户只能看到公开的契约。

接下来的三个小节将分别对设计得当的抽象所具备的几种特质作初步的介绍,稍后还会进行深入的讨论。

A.1.1 极简

根据客户的性质,你可能决定暴露一定程度的实现细节。但问题是,暴露出来的细节一旦公开给客户,就会和客户耦合在一起。所以要确保暴露的细节是为了实现对客户承诺契约要求的必不可少的要件。第A.2节讨论到抽象的极简特质时,会再详谈这个话题。

A.1.2 精炼

设计得当的抽象,必定不能含有核心关注点以外的任何非必要细节。抽象的实现应该达到足够的纯粹度,尽可能减少细节,但又不损失必要的意义。使抽象具备这种性质的过程,是一个精炼过程,我们将在第A.3节详谈。

A.1.3 扩展性和组合性

所谓工程,讲求用模块化的方式来设计事物,并能通过组合进行扩展。除了外部的组合,软件抽象还要能够从内部进行扩展。对于今天设计的抽象,未来也许需要对其补充额外的功能。重点是补充进来的部分不能影响到已有的用户。第A.4节将详细探讨如何用时下的编程语言,实现能够无缝扩展的抽象。

扩展性只有通过组合性来达到。行为得体的抽象,可以组合起来构成更高层次的抽象。但是,怎样才能设计出方便组合的抽象呢?如果抽象的副作用波及到整个执行环境,会发生什么事情?

当你清楚地知道好的抽象具有哪些特质时,对于抽象在领域模型设计中所起的作用就有了评判能力。理解了这些特质,你就会认识到,为什么要把抽象摆到正确的层次上才能保证模型和领域有共同语言。只有这样,你写出来的代码,其表现力才不亚于领域专家所说的行话。