程序原本(七十):应用开发基础——应用开发技术(“没有坏味道”的诀窍:如何更好地组织代码)

阅读数:16 2019 年 10 月 3 日 14:27

程序原本(七十):应用开发基础——应用开发技术(“没有坏味道”的诀窍:如何更好地组织代码)

将数据或逻辑具有类似性质的代码放在一起,或者将逻辑之间存有关系的代码放在一起,这两种思路与面向对象用封装性来解决的问题是相类似的。一个对象,其属性是一系列(具有同类抽象性质的)相关数据,其方法是一系列与上述属性相关或相互间存有依赖的逻辑;对象的封装性决定了对象对外或对某个范围公布的接口。因此,一个对象或这个对象的类,其实有着与“单元”(unit)相同的抽象意义。

所以当面向对象出现之后,“一个单元中应该放多少个类”成了一个问题:如果一个单元可以放多个类,那么它与“库(library)7是用来容纳多个类的组织单元”这一抽象概念又重叠了。因此在早期面向对象语言的设计中,对这个问题的解释是含糊不清的,例如 Pascal/Delphi 允许在一个单元中放任何多个类,这导致“单元的组织原则”变得更加简单而含混:如果类之间相关或相似,就放在同一个单元吧。而晚一些的面向对象语言则较好地解释了这个问题:一个类即是一个单元 / 模块,或干脆进一步地取消了单元 / 模块概念。在具体表现上,例如 JAVA 或 C#就推荐在一个文件中存放一个(可以公开的)类,这个文件——或包含许多函数与数据的单元——将作为一个独立的组织单位存在。

7 这里指的是对象库(object library)或类库(class library),而普遍意义上的“库”是下一小节讨论的重点。

图 36 说明了在面向对象的设计观念中,“类”其实是用来替代“function/unit/ module…”等组织方式。不过在某些多范式语言中,例如 pascal 或 javascript,通常也允许这两类组织方式同时存在。但从本质上来说,这只是代码组织方式决定了一个“代码集”(source code package)在形式上有所不同,其内部的逻辑、数据以及更为底层的算法观念其实是大同小异的。

图 36 “类”的价值与局限:对传统组织方式的一种替代

程序原本(七十):应用开发基础——应用开发技术(“没有坏味道”的诀窍:如何更好地组织代码)

随着系统规模的扩大,应用产品对“引入第三方代码”的需求也越来越明显。而“类”作为一个组织单位,其实是将逻辑和与其相关的数据、相关的抽象目标集中在一起发布,因此面向对象技术提供了相当高的可复用性。这一点正好迎合了上述需求(当然,换个角度也可以说,是需求推动了面向对象复用技术),因而如何在类的基础上进行更大规模的代码组织,成了一个重要的问题。

名字空间(命名空间)的出现与对象复用的思想有着密不可分的关系,但究其本质而言,名字空间下是否包含一个“类簇(class cluster)”却并不要紧。因为名字空间本身只是用于隔离不同的软件厂商、产品和子项目之间的代码,以及这些代码对外交付的接口。这种隔离需求原本是来自于交付物的名字冲突(例如 A 公司与 B 公司的代码库中都存在 TDynamicArray 类),而不是缘于这些交付物的类型或结构抽象冲突。所以无论面向对象是否出现,在“函数 / 单元 / 函数库”这样的组织单位持续进化之后,必然会由于跨公司、跨领域的复用而出现与“名字空间”相类似的代码组织方式。

常见的名字空间的命名规范为:

复制代码
CompanyName.TechnologyName

例如:

复制代码
Microsoft.Office

名字空间可以由更复杂的分类规则构成。例如:

复制代码
Microsoft.Office.Tools.Word.Controls

通常其具体规则是由不同的公司 / 产品 / 产品线来决定的。例如:

复制代码
com.companyName.puc.biz.deduct.data.types
---------------
公司
---
产品 / 系统
-----------
系统层次 / 工程 / 项目组织结构
----
子系统 / 模块
------
系统内定义或其他定义

如同所有的代码组织形式一样,名字空间通常也与作用域相关。由此带来的效果,也就是它解决的需求是:A 公司与 B 公司代码库中的 TDynamicArray 类之所以存在“不同”,是因为它们所处的名字空间不同。这一点与用“单元内、单元外”来隔离标识符系统,以及用函数、语句甚至表达式的“作用域”来隔离标识符系统的性质是完全相同的。它们只是组织规模上的差异,而其抽象概念以及目的是一致的,只是自然地随着规模扩张而延伸罢了。

评论

发布