经验了。
过度编译时耦合与小型项目几乎无关,对于大型项目可能会变成支配开发时间的重要因素。图0-3显示了一个过度编译时间的常见示例:起初看似很好的想法,随着系统规模的增长就会变得糟糕。myerror组件定义了一个MyError结构体,该结构体包含所有可能错误代码的枚举。每个新添加到系统中的组件都理所当然地包含这个头文件。不幸的是,每个新的组件可能有它自己的在主列表中还没有标识出来的错误代码。
随着组件数量的增加,我们将自己的错误信息代码添加到这个列表的愿望将会减弱。我们将倾向于重用已有的错误代码,只是为了避免更改myerror.h文件,这些错误代码大致合适就可以了。最终,我们将会放弃添加新的错误代码的想法,只是返回ERROR或者WARNING,而不更改myerror.h文件。这样做的时候,我们所做的设计就是不可维护并且几乎毫无用处的了。
还有很多其他方面的原因会引起不必要的编译时依赖。一个大型的C++程序常常比等效的C程序拥有更多的头文件。一个头文件对另一个头文件不必要的包含,是造成C++过多耦合的常见来源。例如,在图0-4中,仅因为类Simulator的客户端可能发现对象的定义有用就在simulator的头文件中包含这些定义,这没有必要。这样做迫使客户端依赖于所有这些组件的编译时间,而不管实际上是否需要这些组件。过多的包含指令不仅会增加编译客户端程序的花销,而且也会增加由于在较低层次上改变系统而需要重新编译客户端程序的可能性。
忽略编译时依赖,有可能导致系统中每个编译单元都包含系统中几乎所有头文件,使编译速度慢得跟爬行一样。第一个真正的C++大型项目之一(准确点说,数千人年的工作量)是Mentor Graphics公司研发的一个CAD框架产品。最初开发者不知道有多少编译时依赖会阻碍他们的工作。即使使用我们的大型工作站网络,重新编译整个系统也要花费整整一周的时间。
图0-4中显示的simulator组件在某种程度上举例说明了组织细节的问题。尽管开发出了缓解这一问题的表面技术,但是只有当不必要的编译时依赖被消除时,这个问题才会真正得到解决。
就像链接时依赖的情况一样,也有许多特定的技术适用于消除编译时依赖。