UNIX和面向对象语言:
1980年代中期起,大多数新的语言设计都已自带了对“面向对象”(OO)编程的支持。回想一下,在面向对象的编程中,作用于具体数据结构的函数和数据一起被封装在可视为单元的一个对象中。相反,非OO语言中的模块使数据和作用于该数据的函数的联系变得相当无规律,而且模块间还经常互相泄漏数据或内部细节。
OO设计理念的价值最初在图形系统、图形用户界面和某些仿真程序中被认可。使大家惊讶并逐渐失望的是,很难发现OO设计在这些领域以外还有多少显著优点。其中原因值得我们去探究一番。
在Unix的模块化传统和围绕OO语言发展起来的使用模式之间,存在着某些紧张对立的关系。Unix程序员一直比其他程序员对OO更持怀疑态度,原因之一就源于多样性原则。OO经常被过分推崇为解决软件复杂性问题的唯一正确办法。但是,还有其它一些原因,这些原因值得我们在第14章讨论具体OO(面向对象)语言之前作为背景问题加以探讨,这也将有助于我们对Unix的一些非OO编程风格特征有更深刻的认识。
前面我们提到,Unix的模块化传统就是薄胶合层原则,也就是说,硬件和程序顶层对象之间的抽象层越少越好。这部分是因为C语言的影响。在C语言中模仿真正的对象很费力。正因为这样,堆砌抽象层是一件非常累人的事。这样,C语言中的对象层次倾向于比较平坦和透明。即使Unix程序员使用其它语言,他们也愿意继续沿用Unix模型教给他们的薄胶合/浅分层风格。
OO语言使抽象变得很容易——也许是太容易了。OO语言鼓励“具有厚重的胶合和复杂层次”的体系。当问题域真的很复杂、确实需要大量抽象时,这可能是好事,但如果编码员到头来用复杂的办法来做简单的事情——仅仅是为他们能够这样做,结果便适得其反。
所有的OO语言都显示出某种使程序员陷入过度分层陷阱的倾向。对象框架和对象浏览器并不能代替良好的设计和文档,但却常常被混为一谈。过多的层次破坏了透明性:我们很难看清这些层次,无法在头脑中理清代码到底是怎样运行的。简洁、清晰和透明原则统统被破坏了,结果代码中充满了晦涩的bug,始终存在维护问题。
可能正是因为许多编程课程都把厚重的软件分层作为实现表达原则的方法来教授,这种趋势还在恶化。根据这种观点,拥有很多类就等于在数据中嵌入了很多知识。问题在于,胶合层中的“智能数据”却经常不代表任何程序处理的自然实体——仅仅只是胶合物而已。(这种现象的一个确定标志就是抽象子类或混入(mix-in's)类的不断扩散。)
OO抽象的另一个副作用就是程序往往丧失了优化的机会。例如, a + a + a + a可以用a * 4来表示,如果a是整数,也可以表示成a << 2。但是如果构建了一个类并重新定义了操作符,就根本没什么东西可表明运算操作的交换律、分配律和结合律。既然不能查看对象内部,就不可能知道两个等价表达式中哪一个更有效。这本身并不是在新项目中避免使用OO技法的正当理由,那样只会导致过早优化。但这却是在把非OO代码转换为类层次之前需要三思而后行的原因。
Unix程序员往往对这些问题有本能的直觉。在Unix下,OO语言没能代替非OO的主力语言,如C、Perl(其实有OO功能,但用得不多)和shell等,这种直觉似乎也是原因之一。跟其它正统领域相比,Unix世界对OO语言的批判更直接了当;Unix程序员知道什么时候不该用OO;就算用OO,他们也尽可能保持对象设计的整洁清晰。正如《网络风格的元素》(The Elements of Networking Style)一书的作者在另一个略有不同的背景下所说的[Padlipshy]:“如果你知道自己在做什么,三层就足够了;但如果你不知道自己在做什么,十七层也没用。”
OO在其取得成功的领域(GUI、仿真和图形)之所以能成功,主要原因之一可能是因为在这些领域里很难弄错类型的本体问题。例如,在GUI和图形系统中,类和可操作的可见对象之间有相当自然的映射关系。如果你发现增加的类和所显示的对象没有明显对应关系,那么很容易就会注意到胶合层太厚了。
Unix风格程序设计所面临的主要挑战就是如何将分离法的优点(将问题从原始的场景中简化、归纳)同代码和设计的薄胶合、浅平透层次结构的优点相结合。
阅读(1312) | 评论(0) | 转发(0) |