【 tulaoshi.com - Linux 】
解决复杂性的所有方法都基于一个基本原理:问题分解和各个击破。也就是说,都是把大
型的、难以解决的问题(或系统)分解成一定数量的复杂度较低的子问题(或子系统),
再根据需要重复这一过程直到每一部分都小到可以解决为止,而各种方法只是这种原理的
一些不同运用而已。
计算机科学中有三种经典的方法比较适合于构建大型系统(我首先必须说明的是,这些定
义都是经过我深思熟虑的讨论对象)。
1) 层次(Layer)—将解决方案分解成若干部分,在这些部分中存在一个问题域的最底层
,它为上层的抽象层次较高的工作提供基础。较高层建立在其低层基础之上。OSI和
TCP/IP协议堆栈是众所周知的层次化软件设计的成功的例子。操作系统设计的层次化解决
方案可能会包含一个可以直接和硬件通讯的层次,然后在其上提供为更高层提供抽象支持
的层次。这样更高层就可以对磁盘、网卡等硬件进行访问,而并不需要了解这些设备的具
体细节。
层次化设计的一个特征是要逐步构建符号集(vocabulary)。随着层次的升高,符号集的
功能将越来越强大。层次化设计的另外一个特征是完全可以在对其上下层透明的条件下替
换某一层次。在最理想的情况下,移植层次化的操作系统只需要重写最底层的代码。纯层
次化模型实现的执行速度可能会很慢,因为高层必须(间接的)通过调用一系列连续的低
层才能处理完自己的任务—N层调用N-1层,N-1层调用N-2层,等等,直到实际的工作在0
层被处理完成。接着,结果当然是通过同样的路径反向传递回来。因此,层次化设计通常
会包含对某些高层直接和某些低层通讯的支持;这样虽然提高了速度,但是却使得各个层
次的替换工作更加困难(因为不止一个高层会直接依赖于这个你所希望进行替换的层次)
。
* 模块(Module)—模块将具体的一部分功能块隐藏在抽象的接口背后。模块的最大特点
是将接口和其实现分离开来,这样就能够保证一个模块可以在不影响其他模块的情况下进
行改变。这样也将模块之间的依赖关系仅仅限定于接口。模块的范围是试图反映求解域内
一些方面的自然的概念性界限。纯模块化的操作系统因而就可能有一个磁盘子系统模块,
一个内存管理子系统模块,等等。纯模块化和纯层次化的操作系统之间的主要区别是,一
个可以由其他模块自由调用,模块间没有上层和下层的概念(从这个意义上来说,模块是
广义的层次。按照纯粹的观点,层次是最多可供一个其它模块调用的模块,这个模块也就
是它的直接上层模块)。
* 对象(Object)—对象和模块不同,因为对于初学者来说它们具有不同的问题考虑方式
,实现的方法也可能各自独立。但是,就我们当前的目的来说,对象不过是结构化使用模
块的方法。组件(component)作为对象思想的进一步改进,目前还没有在操作系统设计
中广泛使用。即便如此(按照我们的观点),我们也没有足够的理由将其和模块划分在不
同的范畴中。
图3-1强调了内核的层次化的视图,而且是体系结构无关层次位于体系结构相关层次之上
(更为精确的视图是在顶层增加一个附加的体系结构相关的层次。这是因为系统调用接口
位于应用程序和内核之间,而且是体系结构相关的)。图3-2着重强调了更加模块化的内
核视图。
从合理的表述层次上看,这两种观点都是正确的。但也可以说这两种观点都是错误的。我
可以用大量的图片向你证明内核是遵从所有你所能够指出的设计原则集合的,因为它就是
从众多思想中抽取出来的。简单说来,事实是Linux内核既不是严格层次化的,也不是严
格模块化的,也不是严格意义上的任何类型,而是以实用为主要依据的(实际上,如果要
用一个词来概括Linux从设计到实现的所有特点,那么实用就是最确切的)。也许最保守
的观点是内核的实现是模块化的,虽然这些模块有时会为了追求速度而有意跨越模块的界
限。
这样,Linux的设计同时兼顾了理论和实际。Linux并没有忽视设计方法;相反,在Linux
的开发基本思想中,设计方法的作用就像是编译器:它是完成工作的有力工具。选择一个
基本的设计原则(例如对象)并完全使用这种原则,不允许有任何例外,这对于测试该原
则的限制,或者构建以说明这些方法为目的的教学系统来说都是一个不错的方法。但是如
果要用它来达到Linux的设计目标则会引起许多问题。而且Linux的设计目标中也并不包括
要使内核成为一个完全纯化的系统。Linux开发者为了达到设计目标宁愿违背妨碍目标实
现的原则。
实际上,如果对于Linux来说是正确的,那么它们对于所有最成功的设计来说都是正确的
。最成功、应用最广泛的实际系统必然是实用的系统。有些开发人员试图寻找功能强大的
可以解决所有问题的特殊方法。他们一旦找到了这种方法,所有的问题就都迎刃而解了。
像Linux内核一样的成功设计通常需要为系统的不同部分和描述上的不同层次使用不同的
方法。这样做的结果可能不是很清晰,也不