- 冒号空间 - https://blog.zhenghui.org -

答读者问(2)——关于抽象

答读者问(2)

本贴是临时回答一位读者的提问,匆匆草就,以后有空再整理。长时间未发博,此篇权作凑数。

读者七心葵问:

个人做linux下c/c++游戏开发,上学的时候一度 “抽象” “隐喻” 这类的东西似懂非懂;后来工作后慢慢觉得其实 “抽象”这个词还是很宽泛的,我一般将“抽象”狭义的理解成 OO里面 接口与实现 的提法,即“有选择地忽略”。 但是我认为在计算机科学或工程中,“抽象”一直有其对立面,“反抽象”,也就是《Unix编程文化》里强调的“浅平透”(个人理解),不知郑老师是否看过此书?对于该书尤其是对于“OO”的评价一节有何看法? booch的《面向对象分析与设计》中曾经提到,有人做过统计,几乎所有的设计的方法学大体上都可以分为三类:1 结构化设计 2 数据驱动设计 3 面向对象设计。 对于“数据驱动设计(编程)”,我在工作中经常彷徨于是用c的过程式语言+数据驱动设计呢,还是完全OO化设计,郑老师《冒号课堂》一书中似没有提到多少(个人认为LOP可以看作是数据驱动编程的一种高级形式,也就是DSL或者微语言),是否可以做一个简单介绍?

 

作者hui答:

关于抽象,实是大有文章可做。早就计划就此主题展开一系列的讨论,苦于近来项目缠身,一直无暇顾及。The art of UNIX programming毫无疑问是本好书,但要说unix哲学是反抽象,则不太赞同。事实上,unix成功之处恰恰在于充分运用了抽象。“everything is file”就是最典型的抽象,文件这一概念在unix中的广泛而抽象的应用为unix的设计增色不少。unix提倡”write programs that do one thing and do it well”,便是强调每个小程序都是具有单一职责的抽象功能体。unix推崇filter模式,并极力推荐遵循规范的plain text作为程序之间最通用的接口。unix强调portability比efficiency更重要,而可移植的通常是普适的、抽象的,为了效率则常常“因地制宜”,其结果是以牺牲抽象为代价。(当然这并不意味着抽象是神圣不可侵犯的,也不意味着抽象越多越好)至于”Write simple parts connected by clean interfaces“,“Separate policy from mechanism; separate interfaces from engines“等更是抽象原则的贯彻。 抽象与封装紧密相关,而在字面上封装似乎与透明相对,或许你因此感到”透“(transparency)是抽象的反面?这恐怕是一种误解。其实”透“意味着简单、干净、优雅、可读性(readability)强、规范(specification)清晰、协议(protocol)明确。比如,text文件比binary文件更简单、更”透“,但并不意味着比后者的抽象程度低。相反,私有的(proprietary)文件格式由于规范程度低或不够公开而导致抽象程度较低,对接口的要求更苛刻,与其他程序难以合作,应用起来范围更狭窄或更困难。总之,unix提倡transparency,鼓励接口简单、明晰,以提高代码的可读性、可维护性,让bug难以藏身,这个与抽象性毫无矛盾。另一个类似的常见误解是,把设计上的封装与源码的封闭关联起来,或者以为封装的目的是为了代码的安全性,这些都源于对抽象或封装的认识上的模糊。此外,你提到的“浅、平”,或许指unix提倡的KISS原则(Keep it Simple, Stupid)。不过抽象本不一定意味着复杂、深奥,它只是处理复杂的一种行之有效的手段。如果抽象解决的复杂不及其带来的复杂,则说明该抽象是不当的。文字有时候是有欺骗性的。《冒号课堂》的附注中曾提到一个例子,正是transparent。很多时候它在英文中的意思不是“因透明而看得见”,而是”因透明而看不见“。如果一个接口后面的机制对用户而言是transparent的,正说明它是抽象的,而不是相反。另外值得指出的是,抽象是一个相对的概念,脱离上下文来谈论抽象或具体是毫无意义的。

提到对OO的评价,拥趸固然众多,大唱反调为数亦不少,其中不乏业界名流。如Linux之父Linus Torvalds,STL之父Alexander Stepanov,包括The art of UNIX programming的作者Eric Raymond都曾对OOP作出了十分尖锐的批判。其实名人同样会偏激,甚至比普通人更偏激,因为他们有牛气、有傲气、有底气。他们的批判或许一针见血,但一般人既无深厚的功力,又不了解评论的背景,看看热闹可以,动辄怀疑正在使用的技术就大可不必了。(这就好比一位手持木剑的高手胜了一位手持铁剑的低手,然后不屑地对后者说:其实,木剑更锋利)一切技术都只是工具,决定因素还是使用者对工具的理解程度和熟练程度。相比过程式,OO(准确地说,是融合过程式的OO)从理论上说肯定是更为强大,因为它在前者的基础上增加了新的抽象机制。但如果不理解抽象的本质,为了OO而OO,代码可能比纯粹过程式的更糟。高级的工具并不一定能带来高级的产品。这里多说一句,技术人员在没有达到足够火候的时候,不要随意臧否某项技术。当你尽情吹捧它时,小心背后的陷阱;当你大肆批驳它时,你可能根本未解其妙。淡定,淡定。

Booch提到的三类软件设计方法:Top-down structured design、Data-driven design与Object-oriented design自然都是重要的设计方式,但还存在其他的方法,如event-driven,stream-processing、logic-driven、knowledge-driven等。你提到究竟该用过程式语言+数据驱动设计,还是完全OO化设计,很抱歉,我只能回答:无法一概而论,因项目需求而异、因开发者而异。(不过“完全OO化”从来是不必要的)一方面,不同的项目domain不同,有的侧重数据、有的侧重算法、有的侧重流程、有的侧重交互、有的侧重事件,相应采用的设计与语言也会有所分别。另一方面,与开发者对设计方法和语言的有关,如果你特别擅长C,对C++不熟悉或者不喜欢,那么完全不必一定要用OO。(当然,OO思想同样可以用C来实现)

LOP与数据驱动还是有分别的,它更侧重的主要不是数据,而是某个特殊领域。它通过提高语言的抽象性(更贴近所关注的高层领域逻辑,远离底层语言的细节)来提高代码的可读性、可维护性和开发者的效率。

希望以上简略的回答能对你有所帮助,时间有限,恕未能完全展开。待得空时,会在这方面进行更具体、更深入的阐述。

 

Share