日历

March 2011
M T W T F S S
« Sep   Apr »
 123456
78910111213
14151617181920
21222324252627
28293031  

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

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

 

Be Sociable, Share!
分享/保存
 请您评分1星(很差)2星(不行)3星(一般)4星(不错)5星(很棒) (已有2人评分,平均分为:5.00 / 5)

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

  • 七心葵

    得蒙先生专门撰文答复,深感荣幸,先生针对我的问题做了详细的解答并给出大量的例证,点出了很多我没有想到过的东西。
    需要说明的是我其实是更倾向于OO的,喜欢OO带来的代码的整洁感和易重用,也知道不同的开发方法或语言范型有不同的适用场合,不可一概而论。对于那些驳斥OO的牛人,我不是因为他们是牛人所以怀疑OO,只是觉得他们提出的问题,自己的确得不到解答。上面提出来来的两点,我不认为是足以推翻OO,但是的确认为其有独特的价值(尤其是对比OO来看)所在,因而专门询问这两方面的情况。

    关于我提的两个问题:
    1 OO的抽象的对立面(“反抽象”的叫法似乎太过了,或者应该说是 “反OO抽象”,或者更进一步“反’静态类型的OO’抽象”?);
    2 数据驱动编程;
    我仔细想了想先生的话,并陆续读完了先生的整本书, 还是觉得有些地方想再听听先生的看法,这里写出来,请多多指教。

    ######################################################################################################################################################

    毋庸置疑,抽象是人类处理复杂性的利器。但是,在我看来,“抽象”这个词本身就够抽象,抽象有很多种,有不同角度的抽象,有不同层次的抽象。
    在OO里面,我认为“抽象”通常的定义是“抽象就是有选择的忽略”。那么如果脱离开OO的范畴甚至脱离开软件程序设计的范畴来讲,什么是抽象呢? 很难定义,我们不妨从其反面看,什么不是抽象呢?具体的东西不抽象——具象,或叫做“具体事物”。相比于“抽象”,具象对人类来说显然是一种更直观、更可操控,因而显得更自然、更可理解的思维。

    从这个角度讲,“everything is file”,这里的“file” 其实是一个概念模型,是一个“隐喻”;对比或与非门、0/1编码,它当然是一种抽象,但更是一种具象,因为Unix/Linux 真的把一切都实现成了文件!
    1 你可以所有操作文件的API来操作它,也可以使用用户接口界面CLI通过操作它;你可以直接查看各种真正的文件的内容或属性,也可以通过查看/proc下相应文件来查看进程运行中的内存,还可以通过通过它查看各种I/O数据流。
    2 如果以OO的眼光看,“文件”中的诸多子类型,其实存在“接口退化”的现象,例如:你无法删除/proc目录下表示进程运行时内存的文件(即便你有权限)。

    这里的要点,我认为,是逻辑模型直接映射到了物理实现,因而显得透明,直观,可显,也就是“浅、平、透”。也就是透明性原则的副标题“设计要可见,以便审查和调试”所强调的要点。《Unix编程艺术》(以下称 TAOUP)中强调的其他原则,如 每个程序做一件事并做好,c语言的薄胶合层,文本化协议,多进程分离功能,数据驱动编程,微语言设计,无不体现着这一点:使逻辑模型直接映射到物理实现,可视可显、可以操作、可以度量、可以把玩可以打磨。

    当然,OO设计当然也可以把逻辑设计映射到具体的物理模块,比如分目录的做法,比如分包的做法,比如最终编译为一个动态链接库的做法,都可以将抽象的模块(或层或区) 映射到这样 透明直观可显 的物理实现上,但是我认为这并不等价(尽管分包分库的做法确实已经使得程序的模块性和可理解性变得相对直观很多了)。
    譬如,考虑Apache www服务器最早运行CGI动态生成网页的方式:
    每一个CGI本身作为一个可执行程序,只是从stdin输入往stdout输出,每一个CGI可以通过C语言编写,也可以通过shell,perl等脚本语言编写,其本身既能和Apache配合,也可以在CLI命令行中直接使用、测试、把玩、打磨。并且,CGI还有其他的好处,例如可以按名字按目录控制权限,可以作为一项资源被引用(RESTful架构)等。
    这让人联想到硬件部件具有的长宽高的物理属性,虽然这不是硬件设计的重点,但是一个集成芯片确实可以在关键时候垫桌脚;同样,一个CGI确实可以在必要的时候用作命令行管道中的一个过滤器,而这些都不是那些”由逻辑模块映射成物理模块的动态链接库”等可以做到的(也许能用到一些?比如延迟加载等特性)。

    其实,在 TAOUP 一书中,作者有一次把这些 “已经实现的具象” 称为“基本抽象”:
    (见 第20章:Unix程序员在30年风雨中学到最有经验的回应,就是回到最初的准则–优先从 字节流,命名空间,进程 等 Unix基本抽象中得到更多的效用,而不是增加新的东西。)

    先生一书中曾提到过硬件行业往往因为诸多原因比软件行业更能贯彻OOP的理念,这里的Unix下软件设计这种“保持基本抽象、十分警惕过度纯虚化抽象”的做法似乎更类似于硬件行业的做法。事实上,我认为硬件行业不是能更好的贯彻OOP理念,而是硬件行业的接口标准比较规范(正如书中所述的原因)而不易虚化不易重新制定抽象规范(双刃剑!让人想起来电子垃圾邮件,电子邮件由于其本身的低成本和世界范围内的连通而得以流行,也正是因为同样的原因被发送垃圾邮件的人得以利用并难以预防!)。
    试推想,如果所有的操作系统的API都是符合Posix标准,所有的DBMS都遵从SQL标准,软件行业看起来也会像硬件行业一样规范有序而无需经常抽象!——如果具象层面就能解决的问题,为何要抽象呢;换言之,如果抽象的规范为所有应用软件所遵循,又何必强调接口和实现的形式上分离呢。呵呵,当然没有这么理想化的世界(但是好像硬件行业的世界的确是这样的?或者还是有些变动名堂的吧,要不也不会IDE转USB,USB又转SCSI这样的接口了,当然,这些也是规范化标准化了的),这让我想起来《c++沉思录》中提到的一个笑话,说Lisp程序员在处理那些“不能很好的符合s-expression模式的数据时,他们居然认为解决这些问题的惟一办法就是让全世界都只使用Lisp这一种语言!”(从这个角度来说,OO也许好一点,至少OO在想办法把周边非OO的东西先转化为OO再处理:平的数据文件转变成有嵌套层次的对象,关系型数据库中的数据映射为对象,协议内容包装为DTO对象,简单的值包装成 valueObject,分配内存并初始化 转换为 使用工厂生产对象,原本的功能函数 转变为 serviceObject;UI的对象似乎是天然的,真正映射到现实世界的就只剩下实体对象了!这不正是当年 smalltalk 的困境么?——感谢JVM吧,同时也别奇怪为什么C++程序员总是那么OO得不够专业)

    在这里,与其说Unix文化所强调的是一种抽象,不如说是一种隐喻。抽象只给你接口,隐喻给你必要的梗概信息,以避免“抽象泄露”(见《Joel说软件》一书)。譬如,windows操作系统下,本地磁盘是一个磁盘,一个可访问的异地远程目录也可以挂载为一个磁盘;当你只是打开小文本文件的时候,这两个磁盘(共同的抽象)表现出来没什么区别,但是当你想分别在两个磁盘上运行大型游戏的时候,可能就会发现加载远程磁盘的游戏内容很慢,因为抽象遗漏了一些你在这种情况下必须注意的信息。

    这里我再说我对两个问题的看法:
    1 “透明”
    说到“透明”这个词,我认为“透明”这个词犹如灰色之余黑色白色,说灰色更近于黑色或者更近于白色,其实还是取决于灰的程度如何,因此说“因为透明而看得见”,或者“因为透明而看不见” 应该都是可以的。而在TAOUP一书中,我认为“透明”一词的含义确实更偏重于“因为透明而看得见”,比如该书第20章有这么一段话:
    透明性是重用性的关键,被重用组件不仅要透露给用户“做什么”,还有透露“怎么做”。
    OO的做法显然与这里强调的不同,OO强调封装强调黑盒,只告诉用户“做什么”;这里是白盒,会告诉用户“做什么以及怎样做”。

    2 “文本化”
    text文件比binary文件抽象程度更高更低当然并不一定,但是无结构的文本文件的确是平坦的,和关系型数据库一样,是反OO抽象的(映射成OO时是需要 序列化/反序列化或者ORM 的);但是Unix并不关心于此,Unix关心文本文件内的内容(不论是内容的格式还是字符集)是可显的,透明的,可用来调试,有利于维护,是具象的,直观的,并且可以接合其他过滤器程序处理的,其本身的形式就是元(也许更具体的应该说包括 CSV、TAB键分隔等)。

    以上这些,其实与您书中提到的两种抽象“规范抽象,参数抽象”并不矛盾;
    我从内心深处喜欢OO,OO带给我更多的整洁感和美的享受。而我也总有一些时候认为,也许Unix文化下的这些准则 只是在更小的局部中解决问题会用到的原则等。
    但是数据驱动编程,(我认为其起源于朴素的 参数化思想 和 代码生成技术)则真正的是一种导向与众不同的设计范型。

    ######################################################################################################################################################

    Booch 书中提到的三类软件设计方法:Top-down structured design、Data-driven design与Object-oriented design,(也是引述别人的),我对其中的 Data-driven design (简称 DDD似容易和 domain-driven design 弄混,既然也有叫做 Data-driven programming,我这里简称 DDP)尤其感兴趣,因为我想知道可以和 结构化设计,OO设计 这样并驾齐驱,号称为众多软件设计方法之祖的这样一门编程语言有何奥妙,为何少听人说道?

    这里先说一下我为何愿意相信这三类软件设计方法是众方法之祖,因为:

    1 权威作者的认可
    如 booch 书中所说“这些方法中的大多数基本上都是类似主题的一些变奏”,“绝大多数方法都可以归为以下三类之一”

    2 我个人相信如果从某一个角度看,抓住本质的话,众多的分类可以归并成几类的

    3 逻辑的分析:
    所谓的“软件设计方法”决定了设计软件的方式(-orinted),我认为这3类方法是完全从不同的角度来看待 软件设计的,
    其中 结构化世界 和 OO 不相容在同一个设计中不能并存;而 DDP 则与其他两种方法都各自相容;
    众多编程范式可以归入这3类软件设计方法,例如:
    DDP 其实就是 机制与策略分离,DDP的起源应该是朴素的 参数化抽象 思想, 包含了以下这些编程范式:
    language-orinted programming( declarative programming、function programming、logic-driven、knowledge-driven )
    meta-programming( generic programming、aspect-orinted programming、代码生成技术 )
    而 event-driven 这种范式似乎划归到 OO 中去更为合适,

    TAOUP一书中专门提到了 DDP 和 OO 的对比:
    “数据驱动编程有时会跟面向对象混淆起来…他们之间至少有两点不同。第一,在数据驱动编程中,数据不仅仅是某个对象的状态,实际上还定义了程序的控制流;第二,OO首先考虑的是封装,而数据驱动编程看重的是编写尽可能少的固定代码。Unix中 数据驱动编程的传统比OO更深厚。”
    Booch书中也提到对DDP的描述
    “在这种方法中,系统输入和输出之间的映射关系驱动着软件体系的结构。与 结构化设计 一起,数据驱动设计 已经成功地被应用于一些复杂的领域。”
    这里的“映射关系”我理解为 “机制与策略相分离”的 机制的部分,也对应于 LOP 中的 解释器 或 虚拟机,即“程序中固定不变的部分”。
    因为booch书引用的相关文献我并没有找到进一步参考学习,所以我只是从个人的理解上进行分析。先生内功深厚,涉猎广博,是否可以予以指点?

    按照Tanenbaum在《结构化计算机组成》一书中所言:
    机器的指令系统层提供了底层或与非门,0/1数据,电子部件 的一层虚拟机;
    操作系统在此之上提供了另一层虚拟机(C语言层紧附于这层虚拟机,所以说是一个“薄胶合层”),
    高层语言在此基础上构建更高层的虚拟机(无论是 编译时面对的编译器平台和库 还是 运行时面对的解释器)。

    沿用 Tanenbaum 的观点,我认为 数据驱动编程(包括LOP中的解释器)就是在操作系统层之上再构建一层虚拟机 的过程。
    为什么这么说? 虚拟机之上 和 虚拟机之下 的部分的对比,其实不是数据和指令的对比,也不是虚拟机的软件指令和机器硬件指令的对比,
    而是 相对固定的部分 和 相对易于变动的部分 的对比,是变化率的对比,这正是 数据驱动编程(策略与机制分离) 的本质,是一种朴素的 参数化 的思想。

    数据与代码分离,本质上其实是 相对固定不变的部分(机制) 和 相对容易变动的部分(策略) 的分离。
    数据驱动编程,本质上是符合分离原则和保变原则的,如 bob大叔所说,变化率 是程序始终应该注意的一个问题。
    由此联想到的还有:(数据和代码的分离,微语言和解释器的分离,被生成代码和代码生成器的分离);
    更近一步:(微内核插件式体系结构,)

    元编程 应该说是更加泛化的 数据驱动编程,元编程 不是新加入一个间接层,而是退居一步,使得当前的层变成一个间接层。
    元编程 分为 静态元编程(编译时) 和 动态元编程(运行时),
    静态元编程本质上是一种 代码生成技术 或者 编译器技术; 动态元编程一般通过 解释器(或虚拟机)加以实现。

    数据驱动编程当然也不应该说是“反抽象的”,但的确与 “OO抽象”的思维方式是迥然不同,泾渭分明的,
    如TAOUP一书中所述:“在Unix的模块化传统 和 围绕OO语言发展起来的使用模式之间,存在着紧张的对立关系”
    应该说 数据驱动编程的思路与 结构化编程 和 OO 是正交的,更类似一种”跳出三界外,不在五行中”的做法。
    或许这是您书中言明的,抽象分为”规范抽象”和”参数化抽象”的精义所在?(我不知道您的这两种抽象思想划分的名字来自于何处,但是我很喜欢这一对词)

    考虑 数据驱动编程 与 OO 的不同机制,可以考虑一下 虚拟机 和 类框架 的不同:
    虚拟机将逻辑细节(策略)抛给微语言代码;(只提供域原语,更稳定更灵活)——给用户出的是主观题,要求用户具有一定能力
    类框架提供所有可能的领域组件,供用户组合;(提供了所有需要的东西,比较僵化)——给用户出的是选择题,对用户要求没有上面那么高

    ######################################################################################################################################################
    总而言之,在我看来,TAOUP 强调的这两种Unix世界下的传统 对应于 OO所强调的,可以概括如下:
    1 不强调 数据抽象,但强调模块化封装,强调浅平透的设计,强调直观简单的具象;
    2 不强调 类层次结构,但强调 策略和机制的分离(从而最多2层,策略层再分为 相对固定的部分 和 相对变动的部分 从而形成新的虚拟机层不容易,但不是不可能)
    3 多态本来就不是OO所特有的,Linux内核里面 实现 VFS和各种格式的文件系统时就采用了这种很自然的做法;考虑到 duck type,mixin 等动态语言中的多态机制就更不能如此说了。
    多态对于人类来说其实是很自然的做法,它给程序设计带来了模糊语义,从而使得代码具有更强的表现力,更简单的形式。

    是否可以这么说:有两个世界,OO的世界,和OO以外的世界。
    OO的世界对于程序员来说是理想化的,层次分明,抽象整洁的,非常便于处理复杂性的,各司其职共同协作处理问题的,即您书中所言的公民社会;
    OO以外的世界,具象横陈的世界,其复杂性的来源正如brooks所说 分为本质复杂性(业务本身的) 和 非本质复杂性(技术上的)。
    ——但是在我看来,这些两种复杂性的差别并不在于哪些是业务的哪些是技术的哪些是业务的,而在于哪些是已经被固化下来的。

    某个领域之所以处理起来还比较复杂,是因为:

    1 领域本身的确很复杂:
    a 领域内的逻辑本身的确很复杂,很难有确定的算法来处理
    b 领域内的逻辑还是在变化中的,
    c 领域内逻辑的数量是极大的。

    2 领域基础条件的不成熟:
    a 还没有探索出好的模型,或者该模型还没有被普遍认识到,
    b 还没有制定出好的各个层面的规范并集体遵守,
    c 还没有固化足够多的恰当的机制的部分。

    3 人类心智的限制,一切的背后都有 人的因素 作为依据:
    a 人同时关注的信息数量:7+-2 (所以要分模块)
    b 人接收一组新信息的平均时间5s (所以要简单,系统总的模块数不要太多)
    c 人思维的直观性(人的视觉能力 和 模糊思维能力),这意味这两点:
    A “直”——更善于思考自己能直接接触把玩的东西;(所以要“浅平透”、使用具象的设计),
    B “观”——更善于观图而不是推算逻辑;(所以要 表驱动法,数据驱动编程,要UML,要可视化编程——当然MDA是太理想化了)
    d 人不能持续集中注意力(人在一定的代码行数中产生的bug数量的比例是一定的,所以语言有具有表现力,要体现表达的经济性)
    所以要 机制与策略分离,要 数据和代码分离(数据驱动编程),要 微语言,要 DSL,要LOP,
    e 人是有创造欲,有现实利益心的(只要偶可能总是不够遵从规范,或想创造规范谋利——只要成本能承受,在硬件领域就不行)

    您点出的一句话 “如果抽象解决的复杂不及其带来的复杂,则说明该抽象是不当的。” 可能正点出了要点所在。
    我绝无意批判“抽象”,我只是想说明,的确有另外的思维方式的存在—— 1 直观具象的、浅平透的设计,2 数据驱动编程

    小子浅薄,借贵宝地洋洋洒洒说了这么多,愿得先生指点,解后进心中之惑,不胜感谢。

  • 七心葵

    关于 数据驱动编程 和 OO层级 的区别,忽然想到了一个有趣的类比:
    想想 四种宇宙基本原力 和 “胡克定律”这两种相关但在不同层次的抽象。上帝所设计的!呵呵。四种宇宙基本原力作为虚拟机(机制,或者域原语),之上是各种力的相互作用(策略)最后出现了新的层次上的虚拟机——胡克定律,在此虚拟机机制之上,又会有新的相互作用(策略)。
    但是这里的要点是,总共也才3层,没办法过度抽象过度划分层级,只是固化机制的部分,策略的部分去自由调配,这也许是TAOUP一书中所要表达的意思。:)

  • 七心葵

    此外,我还有一问想咨询先生,据说 面向对象中的继承机制 还可以通过 委托(delegation)的方式来实现,这与现在 java语言中的 动态代理 机制,是否一致?
    我一直觉得这里还有很多发掘点,例如很多设计模式(尤其使用了组合的那些模式)都是在做大量的代理委托;如果这是真的话,那么OO的意义就更被削弱了(当然这不是目的,目的是更好的理解设计的本质);这应该也是隶属于 元编程(运行时元编程)范畴的。
    愿能看到先生这方面的论述。

    • hui

      《冒号课堂》中曾多次提及委托(delegation)(见258页、379页、426页),很多时候它的确是比实现继承更好的选择。至于java中的动态代理(Dynamic Proxy)机制,可用于实现设计模式中的Proxy、Decorator、Adapter等模式 ,同时也是一种特殊的delegation。许多Java框架(比如Spring、Hibernate)都采用了这种技术,但这似乎与OO的意义没有必然联系(OO != 实现继承)。另外,Java的动态代理的确涉及到了元编程。

  • @七心葵
    很高兴能看到如此认真的探讨,不过有的地方,我们的理解不太相同:

    >>在OO里面,我认为“抽象”通常的定义是“抽象就是有选择的忽略”。那么如果脱离开OO的范畴甚至脱离开软件程序设计的范畴来讲,什么是抽象呢? 很难定义,我们不妨从其反面看,什么不是抽象呢?具体的东西不抽象——具象,或叫做“具体事物”。相比于“抽象”,具象对人类来说显然是一种更直观、更可操控,因而显得更自然、更可理解的思维。

    抽象这个词可以是名词,也可以是动词,作为名词的“抽象”是“变化中的不变,不同中的共同”。你前面也提到了抽象是有层次的,即具体和抽象是相对的,并不一定越具体越容易理解。比如,多数人要学会驾驶,并不是一定要深入了解汽车的内部构造,而要学修车则需要了解内部构造,这说明应该了解到哪个抽象层次是和你的目的相关的。另外,当你学会了驾驶,通常你并不会局限在某一辆汽车,这说明你掌握的是一种可以运用于“不同”汽车的“共同”的技术。

    >>从这个角度讲,“everything is file”,这里的“file” 其实是一个概念模型,是一个“隐喻”;对比或与非门、0/1编码,它当然是一种抽象,但更是一种具象,因为Unix/Linux 真的把一切都实现成了文件!

    具体和抽象是相对的,file相比底层0/1编码的抽象层次更高。

    >>1 你可以所有操作文件的API来操作它,也可以使用用户接口界面CLI通过操作它;你可以直接查看各种真正的文件的内容或属性,也可以通过查看/proc下相应文件来查看进程运行中的内存,还可以通过通过它查看各种I/O数据流。

    这正是文件的抽象之处。

    >>2 如果以OO的眼光看,“文件”中的诸多子类型,其实存在“接口退化”的现象,例如:你无法删除/proc目录下表示进程运行时内存的文件(即便你有权限)。

    不认为这是“接口退化”,因为文件权限本身是包括在了文件模型中的,即文件权限是文件的一级属性。

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  

  

  

This blog is kept spam free by WP-SpamFree.