« 引用计数与垃圾收集之比较 | 返回首页 | 推荐几个桌面游戏 »

对面向对象的一些思考

面向对象方法被人谈论了二十多年了。我接触它比较晚,直到九十年代中期才开始学习使用它。若说对这个方法做些评价,那还真是大言不惭了。不过这么些年来,也周期性的对面向对象做些思考。或对或错,我想都值得总结一下。一家之言,来看的同学不必太当真。

首先我们要区分一下“基于对象”和“面向对象”的区别。

基于对象,通常指的是对数据的封装,以及提供一组方法对封装过的数据操作。比如 C 的 IO 库中的 FILE * 就可以看成是基于对象的。

面向对象,则在基于对象的基础上增加了多态性。所谓多态,就是可以用统一的方法对不同的对象进行同样的操作。当然,这些对象不能完全不同,而需要有一些共性,只有存在了这些共性才可能用同样的方法去操作它们。我们从 C++ 通常的实现方法的角度来看,A 和 B 在继承关系上都有共同的祖先 R ,那么我们就可以把 A 和 B 都用对待 R 的控制方法去控制它们。

为什么需要这样做?

回到一个古老的话题:程序是什么?

程序 = 算法 + 数据结构

在计算机的世界里,数据就是一个个比特的组合;代码的执行流程就是顺序、分支、循环的程序结构的组合。用计算机解决问题,就是用程序结构的组合去重新排列数据的组合,得到结果。为了从庞大的输入数据(从 bit 的角度上看,任何输入数据都可能非常的庞大),通过代码映射到结果数据。我们就必须用合理的数据结构把这些比特数据组合起来,形成数量更少的单元。

这些单元,就是对象。对象同时也包括了对它进行操作的方法。这样,我们完成了一次封装,就变成了:

程序 = 基于对象操作的算法 + 以对象为最小单位的数据结构

封装总是为了减少操作粒度,数据结构上的封装导致了数据数据的减少,自然减少了问题求解的复杂度;对代码的封装使得代码得以复用,减少了代码的体积,同样使问题简化。

接下来来看 基于对象操作的算法。这种算法必须将操作对象看成是同样的东西。在没有对象的层次上,算法操作的都是字节,是同类。但是到了对象的层次,就不一定相同了。这个时候,算法操作的是一个抽象概念的集合。

在面向对象的程序设计中,我们便少不了容器。容器就用来存放一类有共同抽象概念的东西。这里说有共同概念的东西,而没有说对象。是因为对于算法作用于的集合,里面放的并不是对象实体,而是一个对实体的引用。这个引用表达的是,算法可以对引用的那一头的东西做些什么,而并不要求那一头是什么。

比如,我实现一个 GUI 系统(或是一个 3d 世界)。需要实现一个功能——判断鼠标点选到了什么物件。这里,每个物件提供了一个方法,可以判断当前鼠标的位置有没有捕获(点到)它。

这时最简单的时候方法是:把所有可以被点选的物件都放在一个容器中,每次遍历这个容器,查看是哪一个物件捕获了鼠标。

我们并不需要可被点选的物件都是同类,只需要要求从容器中可以以统一方法访问每个元素的是否捕获住鼠标的这个判定方法。

也就是说,把对象置入容器时,只需要让置入的东西有这一个判定方法即可。了解 COM 的同学应该明白我要说什么了。对,这就是 QueryInterface 的用途。com 的 query interface 就是说,从一个对象里取到一个特定可以做某件事情的接口。通常接下来的代码会把它放在一个容器里,方便别处的代码可以干这些事情。

面向对象的本质就是让对象有多态性,把不同对象以同一特性来归组,统一处理。至于所谓继承、虚表、等等概念,只是实现的细节。

说到这里,再说一下 COM 。COM 允许 接口继承 ,但不允许接口多继承。这一点是从二进制一致性上来考虑的。

为什么没提 实现继承 的事情?因为实现继承不属于面向对象的必要因素。而且,现在来看,实现继承对软件质量来说,是有负面影响的。因为如果你改写基类的虚方法,就意味着有可能破坏基类的行为(继承角度看,基类对象是你这个对象的一部分)。往往基类的实现早于派生类,并不能了解到派生类的需求变化。这样,在不了解基类设计的前提下,冒然的实现继承都是有风险的。这不利于软件的模块化分离和组件复用。

但是接口继承又有什么意义呢?以我愚见,绝大多数情况下,同样对设计没有意义。但具体到 COM 设计本身,让每个接口都继承于 IUnknown 却是有意义的。这个意义来至于基础设施的缺乏。我指的是 GC 。在没有 GC 的环境中,AddRef 和 Release 相当于让每个对象自己来实现 RC (引用计数)的自动化管理。对于非虚拟机的原生代码,考虑到 COM 不依赖具体语言,这几乎是唯一的手段。另外 COM 还支持 apartment 的概念,甚至允许 COM 对象处于不同的机器间,这也使得 GC 实现困难。

QueryInterface 存在于每个 COM 接口中却有那么一点格格不入。它之所以存在,是因为 COM 接口指针承担了双重责任,既指出了一个抽象概念,又引用了对象的实体。但从一个具体算法来看,它只需要对一组相同的抽象概念做操作即可。但它做完操作后,很可能(但不是必须)需要把对象放入另一个不同的集合中,供其它算法操作。这个时候,就需要 QueryInterface 将其转换为另外一个接口。

但是,从概念上讲,让两个不相关的接口相互转换是不合逻辑的。本质上,其实在不相关的接口间转换做的事情等价于:从一个接口中取得对对象的引用,然后调用这个对象的方法,取到新的接口。

如果去掉了 AddRef Release (依赖 GC )以及 QueryInterface (只在需要时增加一个接口获得对象的引用),IUnknown 就什么都不剩了。那么接口继承也完全不必存在。


回头再来看程序语言。

C++ 提供了对面向对象的支持,但 C++ 所用的方法(虚表、继承、多重继承、虚继承、等等)只是一种在 C 已有的模型上,追加的一种高效的实现方式而已。它不一定是最高效的方式(虽然很少能做到更高效),也不是最灵活的方式(可以考察 Ruby )。我想,只用 C++ 写程序的人最容易犯的错误就是认为 C++ 对面向对象的支持的实现本身就是面向对象的本质。如果真的理解了面向对象,在特定需求下可以做出特定的结构来实现它。语言就已经是次要的东西了。

了解你的需求,区分我需要什么和我可以做到什么,对于设计是很重要的。好的设计在于减无可减。

你需要面向对象吗?你需要 GC 吗?你需要所有的类都有一个共同的基类吗?你需要接口可以继承吗?你为什么需要这些?

Comments

膜拜ing

太赞了。看完文章和评论,受益匪浅。

看东西的层次问题。
面向对象是帮助人来理解代码的方式。
就象我看见灯
我只需要知道:我一拉它就亮。

我不关心他是什么样的灯 在客观世界就是有各种的标签 这些标签形成了我们的认知。

不明何谓“减无可减”。
代码量?
数据量?
还是接口规模?
--
只知3NF,5NF等早已对某些东西有所指明。

唉,我们这些浅薄的程序员,也不过是讨口饭吃,也许是我意志薄弱,曾经想成为高手的想法已经不知道藏哪里去了

所谓的设计模式,n多类其实在直接和OS打交道的领域里,都是垃圾

@ghost

这样看来我和你的看法又没什么大的出入。只是我说得没你那么详细而已。
曾经也在改别人的错误,也曾自己获过错误,后来是被逼着去重复错误,接着是辞职,呵呵。不过这样的公司还真不少:(
那现状如此,除了一气走人,坚持走自己的路,我们于大环境又能改变什么呢?
或许真的没那些有着花哨名词的新技术,会多几个潜心修行的开发者。

看ghost的发言,让我有一种泄愤的快感:)

但是,从概念上讲,让两个不相关的接口相互转换是不合逻辑的。本质上,其实在不相关的接口间转换做的事情等价于:从一个接口中取得对对象的引用,然后调用这个对象的方法,取到新的接口。


有趣的是,对于COM来说,不光“本质上”类型转换等价于方法调用,“实际实现”也是如此。

好的设计?
那么什么才算是好的设计呢?
高效?简洁?扩展性?维护性?
评价的标准似乎很多。但是那似乎也只是理论而已。
设计人对项目的理解和把握,曾经的项目经验,甚至学习经验。项目本身的要求?

“正因为设计如此重要,所以必须禁止外行染指这个领域。”
“禁止”是人为的壁垒,而不是知识壁垒。

回 zen_yue朋友:

1、设计是最最重要的。没有好的架构设计,万字就要画一万横。
正因为设计如此重要,所以必须禁止外行染指这个领域。
这不是什么行业壁垒,而是知识壁垒。

20个线程读磁盘,真正懂得计算机、真正动手做过东西的一定会感到可笑,进而担心这个项目的命运。

不仅仅是数据结构和算法,UML、面向对象还有设计模式都是必要的好东西——飞机也是好东西;但绝不应让拉登等心智还不健全的原教旨主义分子接触。

2、如果你觉得Linus Torvalds居然像个小P孩般去争论语言的优劣,那么你也把他看得太低了些。

仔细品品他话里的味道吧。

明确点说,就是:C++和UML一样,是一种威力强大的好东西。但正因为它的强大,仅仅学会“用VB编计算器”的家伙就多了起来。

由于缺少对计算机真正深刻的理解,这些C++语言专家就觉得一切也不过如此,按照对象发现方法论把类啊模式啊往上一套,一切就都有了;甚至于有了相关知识后,他们还是脱离不了那些可笑的固定套路——这就是所谓的心智包袱。

必须明白:没有任何一种方法论可以告诉你“不能用20个线程读同时读写磁盘”以及诸如此类的其他东西。

如果法律执行严格,这些浪费了纳税人数千万的不称职的家伙,处境相当危险。

但显然,这些人的自我感觉还是非常良好的。从他们自称“白领”并且想用机器替代“蓝领”便可见一斑。
他们不知道,自己的一只脚就在牢门里放着。

能把一个好好的人整成这样,你说C++以及UML、设计模式算什么?


3、正因为人才难找,这才彰显能干活的软件“蓝领”的重要。

追加投入100亿,给他们100年,你觉得我说的那帮子“白领”能把东西做出来吗?

给你100万,但必须承担项目失败的后果;你愿意以“不修改高层设计”的前提接下那个“以O(N^2)效率存储用户信息、数据库存储程序状态却又让其他模块无限制访问、20线程玩磁盘、5000并发用户连接用5000个进程实现且5000个进程无任何锁自由访问(包括添加和删除!)同一块共享内存里的session、并且认为单核CPU根本就不可能出现并行因而不管多少线程访问同一块内存都不需要锁”的“白领”项目烂摊子吗?


一个破网上超市项目而已,不考虑用户界面,内部逻辑在云风这里可能就是一两个月;而且做出的一定还是通用内核(连我都觉得这是个半年单人干的活!)。

但那帮家伙楞是做了好几年,花了数千万!


没有人说方案不可以折中,不可以靠牺牲某些东西以绕开技术难点——相反,能够做到这个的,才配叫技术人才。

是的。企业不需要天才,他们只需要开发人员能把任务完成。

问题是:你用哪只眼睛看到,只要会画画UML、像“学用VB编计算器”一样玩玩对象发现,就能“完成而且低成本高效率的完成任务”?

那些在监狱门外徘徊的白领们的教训,还不够深刻么?


现在根本的问题不是什么“开发/设计人员的实力”,而是把草包剔除。

当这些草包滚蛋之后——只要有类似云风这样懂技术的主心骨在,把核心做了,剩下的直接上lua或其他脚本即可:这时候,对开发人员的素质要求才可能真正降下来。


——相反,当初在草包的手下,我们几个会干活的那可是名符其实的“救火队”:从数据库性能不足需调查原因、到莫名其妙的偶发crash(被我查出原因是线程退出次序紊乱)、再到“由于一点点设计疏漏,我们要帮另一个模块更新数据库状态”、继而“由于对方数据库负荷过重,那个更新导致我们的服务失去响应”(为这个,我不得不写了个自动管理线程及相关资源的小调度模块,以保证主逻辑里可以像函数调用一样完成数据库异步更新工作——并且这个模块的健壮性必须达到7×24小时级别;由于这个200多行代码写的模块太干净利落了点,导致另一个想当“白领”的家伙对我产生了警惕,从此时时处处给我下绊子!)……

这份“蓝领”的工作看起来如何?您拿得下吗?

人贵有自知之明。
对初学者来说,千万要明白画UML、玩面向对象、看设计模式等等花活和真正的项目设计之间的区别。
在工程师的世界里,一个算法可能都值得很多人研究一辈子;甚至他们的后人还要接着研究;或者,他会知道关于软硬件的一切,然后小心翼翼地引领团队绕开一个个陷阱:而为了这个,他需要懂得一切,甚至包括生物学(比如遗传算法、神经网络以及人眼人耳的物理原理及特性等等等等)——这些都和管理者的“浅薄(无贬义)”的世界在根本上是不同的。

不打算在engineer的世界里投入一辈子的,可能是好的engineer吗?

我是个新人,读了ghost的回复,觉得说的没错,但有些地方难以理解,接受不了。对一个软件难道设计不重要吗?除去说什么对象与模式的,至少也要设计个数据结构与算法吧。
对于我,虽然有用起来不喜欢的语言,但没有觉得什么是垃圾的语言。存在就有它的道理,或许只是你不需要而已。
人才是难找的,你不可能要求每个开发人员都有天才般的开发实力,但项目必须完成,有些东西就是折衷的方案。企业要的不是一个天才的团队,而是一个能完成项目,同时低成本,高效率(依靠某些工具或方法)的团队。一般都以设计做主导,如果设计出问题,无疑项目会一团糟,但假设设计没有问题,那项目就有可能接近理想。
所说的管理者与工程师的问题,哎,管理者不该涉及系统设计与程序的。项目经理应该只负责调度,当然如果他是个牛人,能说善听,精力旺盛,程序写得顶呱呱,兼个架构师的职位也没什么不可以。
发现是看的方向不太相同,似乎也没什么好讨论的:(
还是那句话,存在有它的道理。发现这个道理就知道该用在哪里。没发现前也用用吧,不用又怎么会明白其中的道理呢。用完,记得深思,审视。
嗯,看完,也提醒自己再审视一些东西。

Q1:你需要面向对象吗?
A1:需要,在设计时会使我的思路更加清晰,可扩展性可读性上都得到很大的提升。
Q2:你需要 GC 吗?
A2:需要。使我写代码时比较安心一些。
Q3:你需要所有的类都有一个共同的基类吗?
A3:通常时候会用大部分类继承于某一基类,原因如A1,良好的抽象的设计能很大程度上方便之后的工作。
Q4:你需要接口可以继承吗?
A4:是的。有接口,容易扩展,并且为若干时间后的补充提供一套规范。
Q5:你为什么需要这些?
A5:综上。
OO并没有错,是好东西。语言之争实在没意思的很,就象砍木头,愿意用锯还是愿意用斧头有什么区别。关键是使用工具的人怎么想。

说实话,感觉这篇文章,有点怪。对于“基于对象”“面象对象”这种咬字眼的东西实在不感冒。

你的心智,到能够继承它们的时候了吗?

好文共赏!受教了!

呵呵,我倒觉得,现在颇有些人以为拿ROSE画UML就是“面向对象软件设计”了。

事实上,所谓的“对象发现”、用例设计等等东西,和“跟我学用VB编写计算器”,在水平层次上毫无差异。

其实,虽然宣传起来吹得很大,rose还是相当清楚自己的定位的:一个专业程序员和普通用户间的交流工具。

用一位外国朋友的话来说就是:这东西是manager's world用来沟通user's world和engineer's world的。

用户基本没有关于计算机知识;他只能说出他的工作是什么;manager善于沟通,但对程序设计并不精通;engineer虽然精于程序设计,但往往并不善于与人打交道。

借助UML和用例以及对象发现,manager可以做出一个虽不比“用VB学编计算器”更高明、但至少不能算是外行的初步框架——这是对engineer来说的。
而对于用户来说,UML避免了engineer随口说出的术语,给出了一个虽然样式有点怪异、但毕竟不算难懂的模型。

于是,三方皆大欢喜,这事就这样成了。


但是,倘若manager学了个“VB写计算器”的方法,便以为engineer们的时代过去了,一切有他和机器足矣;那么大家就应该知道,是该给什么医院打个电话的时候了。

比如,我之前提的那个“每天50G以上日志;单个日志文件小于2M;每天定时分析此日志;消耗时间尽可能少”的需求,你拿UML+用例+对象发现 能捣鼓出什么?!

manager只要能确定如上需求,他就已经非常优秀了;但适可而止吧,再多走一步就是犯罪(现实是:数千万已经这样打了水漂了;而且显然还要继续投入更多的钱打水漂!)

相反,这东西在我们engineer手里,又怎么样呢?
我们马上就会想起,一次拖10个1G的文件到另一个硬盘可能需要10分钟;但一次拖一个文件,让10个拷贝操作同时运行,可能就要几个小时。
由我们的专业知识,很容易知道这是因为乱序访问磁盘,导致出现大量磁头寻道操作所致。
于是,正确的方案就摆在面前了。
(相反,那些玩过界的manager们搞了20个线程同时到磁盘上瞎玩——想想情况会有多可怕吧)


国外对这些区分的是非常清楚的。
所谓manager,他只是资源的管理者——资源当然包括人力资源在内。
但必须强调,他只是被赋予权力调度各种资源以尽可能高的效率完成工作,并不是engineer的上司:双方根本就不是同一个世界的人。

在国外,从engineer世界转到manager世界的人,往往是会被真正的engineer鄙视的。因为这说明他根本就不喜欢或做不了engineer的工作,在engineer的世界里没有发展前途。

(事实上,manager不过是个管家类型的人才;engineer才是真正可以被称作“学者”的。双方的社会声誉是相差极大的。不管做管理的做到什么程度,做技术的都能以一句“just a manager”噎得他喘不过气。)

说这些,我的意思当然不是说做管理的都是些没文化的家伙。
沟通是门艺术;在下就极不善于口头沟通,对嘴皮子厉害的人,当然是相当仰慕的。
——但艺术毕竟不是学术。

要说水深,再没有比学术淹死的人更多的了。

国内的情况大家都很了解,不多说了。

但有一个极其严重的问题必须再提一提:由于官本位思想作祟,我们的manager太具侵略性了。
这些家伙,和那个学会一横是“一”、两横是“二”、三横是“三”,便敢宣称“儿得矣”的小屁孩是一路货。

小屁孩揽下个写“万”的任务,险些把自己累死。
同样,我们刚学会“用VB编计算器”的manager也能搞20个线程把磁盘累死;搞个O(N^2)的算法处理千万级别的数据把数据库服务器累死;搞个大蜘蛛网把自己也累死——最后,倘若法律能更完善,被他们葬送的数千万恐怕已足以将此等人送上刑场;起码也得好几年牢坐。

但没关系。这里是中国。这里是软件“白领”们正要用机器替代软件“蓝领”的中国。

受这些脸皮足以挡子弹的家伙影响,准备先做几天技术然后转管理的家伙越来越多——原因嘛,管理人员早已远远过剩,能做技术的却是千百人中都挑不出一个(这是实话,没有半点夸张)。

所以,即使学个半吊子,也能混上个技术工作;干上两年——我们很多公司根本就没给做技术的准备升职路线——自然就升职做管理了。

另一方面,为避免其他做技术的抢到自己的位置,他们自然要大力宣传“蓝领”论,拼命打压真正做技术的。

在这种浮躁的气氛下,大量涌现只会写一二三的小屁孩,也就不足为奇了。

毕竟,死记硬背几条C++特性,要比彻底理解计算机软硬件原理、理解算法原理以及相关的数学甚至物理知识,要容易太多太多了。

PS:Linus Torvalds骂的不是C++,而是学了几条C++基础知识就不知道天高地厚的小屁孩;是那些学会“用VB写计算器”就自以为是软件白领的人:

C++是一种糟糕的(horrible)语言。而且因为有大量不够标准的程序员在使用而使情况更糟,以至于极容易产生彻头彻尾的垃圾(total and utter crap)。老实说,选择C就是为了把C++程序员踢出去。……我有这样的结论,任何喜欢用C++而不是C开发项目的程序员可能都是我希望踢出去的人,免得他们来搞乱我参与的项目。C++会导致非常非常糟糕的设计选择。你们这些C++程序员总是一上来就用语言的那些‘漂亮的’库特性比如STL、Boost和其他彻头彻尾的垃圾,这可能对你们的程序有所‘帮助’,但是却会导致:

“——当库无法工作时无穷无尽的折磨(别跟我说什么STL尤其是Boost很稳定而且可移植性很好,那全是屁话,而且一点都不可笑)

"——低效的抽象编程模型,可能在两年之后你会注意到有些抽象效果不怎么样,但是所有代码已经依赖于围绕它设计的‘漂亮’对象模型了,如果不重写应用程序,就无法改正。


”也就是说,使用优秀的、高效的、系统级的和可移植的C++的唯一方式,最终还是限于使用C本身具有的所有特性。项目限制只用C,意味着参与的人不会捣乱,也意味着会得到许多真正懂得底层问题,而不会折腾那些白痴‘对象模型’垃圾的程序员。

"所以,我很抱歉,但是对于Git这样效率是主要目标的软件,C++的所谓优点只是巨大的错误。而我们将看不到这一点的人排除在外却成了一个巨大的附加优势。

"如果你想要用C++写的版本控制系统,去玩Monotone吧。他们确实使用了‘真格的数据库’,使用了‘漂亮的面向对象库’、使用了‘漂亮的C++抽象’。可是说老实话,所有这些对某些计算机专业人士而言富于吸引力的设计决定,其最终结果确是一堆可怕、难以维护的垃圾。“


尤其是这些:

唯一真正重要的部分是设计。

"你当然可以用任何语言编写糟糕的代码。但是,有些语言,尤其是带有一些心理(mental)包袱的语言本身就非常糟糕。你这样的新手跑来指出一些绝对无关紧要的补丁特性,用它们作为一种语言优越的论据(这些东西语言原作者都不喜欢),这一事实本身恰恰说明你满脑子都是糊涂概念,应该好好醒悟一下了。

不仅指语言本身,还包括一种必需的心态(mentality)。C最大的优点之一,就是它不会使你认为程序是什么高层的东西。正是后一种心态会使你明显偏向其他语言,但实际上从Git的角度看来,所谓 ' 高层 ' 恰恰是错误的。"


其实,不光是C++;面向对象、UML以及新近晋升为祸害的设计模式,不都是这样吗?

举例来说:打开老爸的工具箱,你会发现钳子、扳手、刀子、电锯、机油甚至硫酸、剧毒杀虫剂和极易爆炸的氧炔焊接装置。

你的心智,到能够继承它们的时候了吗?

"我想,只用 C++ 写程序的人最容易犯的错误就是认为 C++ 对面向对象的支持的实现本身就是面向对象的本质。如果真的理解了面向对象,在特定需求下可以做出特定的结构来实现它。语言就已经是次要的东西了。"
===>
我喜欢这句话.

简洁清晰,一般来说我会这样要求自己设计。如果无法一目了然的了解程序在做什么。那么一般我会换一个方式来思考。unix其实设计得很精妙,设计模式说白了在很大程度上是在用面向对象的方式实现unix在几十年前所提出的那些关于软件设计的精神。

为了避免误解,小心翼翼地, 我强调,这是指参与的讨论而言,而不是文章本身

剥离了在应用和工程中创造的无数拗口生僻的名词, 所有的概念基础存在于学校课本里,存在于数学书中,学生应该掌握,

面向对象谈论这么多年, 似乎工程师谈论的都是具体语言措施里的实现, 反复, 没有理论的一个概括.

表面上, 面向对象方法,设计模式, 统称为“方法论”, 奇怪的名词,这些东西看似一半的理论,给人以无数著书立说的可能, 因为讨论方法嘛,没人说对错,

对啊, 面向对象, GC...你为什么需要这些, 工程师们,处于一个缺乏理解的时代,

编程模式越来越纯粹, 相关的理论基础早以存在,却一直没被工程师理解而已, 一切美好的东西, 淹没在工程的复杂性里面

毫无疑问,这种几乎属于玄学的讨论,吸引了最多人的讨论, 因为很难有硬伤:)

有一个问题,你的blog在屏幕上怎么只有那么一点点宽,能不调到0.618那个范围,不然看起来有一点儿不爽,不过blog内容还是有趣的

你需要面向对象吗?
你需要 GC 吗?
你需要所有的类都有一个共同的
你需要接口可以继承吗?
你为什么需要这些?

非得不用,非利不动,非危不>

如果对程序设计而言,能够减少耦合,提高内聚,增加稳定性,减少代码量及资源占用的设计就是好设计。实现这些目标有N种方法,前人不断实践与总结,所以有了函数,结构,面向对象……各有各有好处,各有各的应用范围。最近做些东西,发现在C++中,有些实际情况坚持应用某一方法是不太理想的,或许得看需求,舍弃一些设计上的统一。我比较向往灵活性与安全性,但对资源占用并不很在意,除非项目明确规定,运行在某某平台上。因为软件要向前发展,硬件也是,如何让软件更上硬件发展的脚步,保持原来软件的灵活性很重要。基于这样的考虑,接口应用是一种不错的实现手段。方便,直观。而谈到设计层面来,似乎可以是语言无关的东东,当你设计完你的系统,再根据性能需求选个工具来开发,如果选了C++,再审视一下设计,发现有个GC不错,那么就做个GC吧。其实程序跑起来,硬件也只需知道数据在那,指令在那也就行了。N多方法只为了方便我们的开发与维护。明确目标选工具,而不是拿个工具来套目标。愚见!

小平说, 先搞清楚什么是社会主义, 才能怎样建设社会主义;
1. 贫穷不是社会主义;
2. 两级分化更不是社会主义;

不妨我们也应用一下:
在我们阔谈如何"建设"类之前, 首先定义一下到底什么是"类":
1. ????
2. ????

我对OO的理解和云风差不多,就是OB+多态,便于以相同方式遍历操作相似的东西。

囧……有个问题……
有多少人调查过到底有没有方形的或者非圆形的下水道盖子?

@Zenberg

GP愚以为并不是OO的补充,范型编程其重中之重是一个“范”字,编程已是其次,“范”明显的代表了抽象的意味,如果在C上去作泛型编程,大概亦只能用void*作接口,但丝毫不影响其实现。现在我比较喜欢用接口这个词,其本身就有一种抽象的意思。诚如贵言:“linux对待不同文件系统的实现的接口设计和collection framework抽象不同行为模式容器的接口设计实在是异曲同工。”,抽象出接口后,C写就的linux kernel和以Java写就的collection framework如何实现已不重要,本人愚见,这就是所谓的泛型编程(GP)。

确实,一种语言会对程序员产生导向。但是作为一个程序员,不是应该把握好各种导向,站在更高层次,构思抽象,充分利用各种语言的特色吗?当然混合各种语言的编程是天方夜谭,但是可以充分利用接口的功用,结合不同的语言,例如C/C++与LUA脚本的结合,愚以为亦是GP的一种表现。

我觉得,作为一个程序员应该去发挥各种语言的特色,而不是去矮化各种语言。

@Cloud

我也不想探讨设计模式,因为我实在没有发言权,我举例不过为了说明抽象的重要性,实现是其次的。

“那么,怎么提取这些共性。”“重要的是理解你的需求,判别哪些是真正的需求,哪些是不必要的需求。”
大概这些就是抽象的工作了,用什么实现这里一点都不重要。

“举例,GP 也是一种抽象的手段,但 GP 不是 OO 。GP 的抽象主要解决的是在不同的地方用相同的算法去处理不同类别的东西。

而 OO 做的是什么呢?OO 做的是把不同的东西归类在一起,在同一地方处理这些东西具有共性的部分。这就是多态。”

按照我的理解,方法和数据都是有“接口”的,因为方法期望合法的数据,所以数据也需要提供访问的接口,在C语言中,你可以提供一个方法的接口或者一个数据的接口,但是在OO中,你可以拥有方法和数据的共同体。两者抽象的本质却是没有分别的。

===================
本人才疏学浅,见笑了,还望指教。

并非任何软件搭建都会强调抽象和封装的,软件危机的原因产生大概就在于此。

OO的好处是强制你去进行抽象和封装,至少会让开发者去在这方面做思考。其实我们尽可以去用Java写Procedure形式的程序,也可以用C去OO,当然这并不是问题的关键。

GP与OO并不矛盾,就如楼主所说,只是不同角度而已,我个人觉得GP是对OO非常好的一个补充。

以本人有限的认识,我觉得以C写就的linux kernel和以Java写就的collection framework都是令人击节的OO实践杰作。

linux对待不同文件系统的实现的接口设计和collection framework抽象不同行为模式容器的接口设计实在是异曲同工。

再,我个人认为你对封装和抽象的理解有问题,并非问题粒度上的事情。

抽象是为了对各类需求进行分门别类的管理。

封装是为了隐藏实现的细节,进而达到抽象的目的。

@joe wulf

我举鼠标选取的例子,不是想探讨设计模式,我认为模式固然有用,但是大多数情况下会让我们忽略本质。这点我跟 ghost 的看法近似。

那么我想说明什么?

在这个例子里,我们的本质需求是:可以需要让不同的对象可以用统一的途径去检查是否捕获住鼠标。只要满足了这个,就可以把这些对象放在一起来处理。这就是 OO 在这个问题上作用。

至于之后怎么办,无非是顺序、分支、循环而已。我们不需要看到什么模式,因为要处理的事务和数据的粒度已经足够粗了,基本的算法就能搞定它们。

那么,怎么提取这些共性。COM 的 QueryInterface 就是描述的这个问题。字面的意义解释的恰到好处。至于如何实现它,用继承只是解决方案之一。当语言提供了某种便捷的语法手段时,我们就倾向于把实现手法偏向于它。所以语言本身就对程序员的思维造成了导向。

对于一个特定问题,有一个解决方法。但是对于许多问题的集合,把逐个解决方法糅合到一起却十分危险。因为每针对一个问题的解决,结构的设计都有差别。把他们组合到一起,结构(数据结构和代码结构)就容易变成一团乱泥。

我想,为了最好的解决问题。设计方法和模式都是次要的东西。重要的是理解你的需求,判别哪些是真正的需求,哪些是不必要的需求。(通常是因为你为了解决那些真正需求,铺了一条路。而后为了铺路而产生的新需求。)

留下那些真正的需求,把问题简单化。

@Zenberg,

正文中列出哪些问题,是提醒自己和各位同学,在做每个项目前,都仔细考虑这几个问题。这些问题是个要解决的问题相关的,有时候我们需要,有时候我们不需要。而不是抛开要解决的问题,直接可以得到答案的。我绝对没有排斥这些的意思。但只有真的明确了我们必须用这些才能得到良好的设计,这个时候再动手。

另,任何一种搭建软件的方法,都会强调抽象和封装,它并非 OO 特有。封装是为了减少要处理的问题的粒度。抽象是为了可以在封装过的粗粒度上进行操作。

举例,GP 也是一种抽象的手段,但 GP 不是 OO 。GP 的抽象主要解决的是在不同的地方用相同的算法去处理不同类别的东西。

而 OO 做的是什么呢?OO 做的是把不同的东西归类在一起,在同一地方处理这些东西具有共性的部分。这就是多态。

先大略浏览了一遍,然后细看一遍评论,再细看一遍文章,我亦蠢蠢欲动,即使我才疏学浅。
我学习编程亦不过五六载,不过代码量不上万行(其中COPY.PASTE的可能占50%),可能因为我比较向理论派倾斜。
依我愚见,是否面向对象,亦只不过是实现的一种方式,而在实现之上,思想才是最重要的,COM正是如此,统一的接口体现的是一种抽象的思想,无论你是用C、C++或者PASCAL,只要你实现了相关的接口,就能向外界提供服务。
说到接口,无不以JAVA为例,可以说JAVA的接口是多继承的一种模拟,实现接口就是告诉我们,我提供了这个方法可以供你调用。其实说到“程序 = 算法 + 数据结构”这个公式,不能不提一下,其实大家都知道算法是和数据结构分不开的,算法就是提供一个数据输入的接口,然后通过特定的处理,返回结果,而相关的数据结构也需要有对于的接口,否则访问不了其内部数据,二者就不能结合起来成为程序了。以我看来,却是无处不接口了。不知道接口是属于过程,还是属于对象的?
另外提一个经典的问题:为什么下水道的井盖是圆的。其实很简单,因为井口是圆的,它提供了一个圆形的接口,所以它期望一个圆形的盖子,由此你不得不设计一个圆形的井盖。
废话这么多,好像离题了。其实面向对象最重要的是其抽象的思想,而不是其多态的实现。近来也看了HEAD FIRST的设计模式,不过没看完。诚然,设计模式是一种思想(都是基于面向对象的,至少我没看见基于C的),它可以用C++、JAVA或者C#乃至任何面向对象的语言实现,足以证明实现是不重要的。每个语言都有自己的特征,实现不过是利用语言各自的特征作出最高效率的处理罢了。
总结一点,免得太乱没人看懂我说什么:面向对象、面向过程不过是实现的一种特定的方法,没有最好的方法,只有最适合的。
========================
Quote:
比如,我实现一个 GUI 系统(或是一个 3d 世界)。需要实现一个功能——判断鼠标点选到了什么物件。这里,每个物件提供了一个方法,可以判断当前鼠标的位置有没有捕获(点到)它。

这时最简单的时候方法是:把所有可以被点选的物件都放在一个容器中,每次遍历这个容器,查看是哪一个物件捕获了鼠标。

例如这里,就要按你的思想来实现了,如果前者,你可以使用Observer,如果后者,你可以使用Iterator。实现是最低级的。
========================
下面我来回答一下“面试题”:
1。你需要面向对象吗?
要的,不然我的设计模式没用处。
2。至于GC,我完成没有相关的编程EXP,所以在此亦不过纸上谈兵而已。GC的重要性无容置疑,至于云风所提出的“你需要 GC 吗?”,我以为应该按需而论,就一个系统的完整性和强壮性来说,一套完善的GC无疑是一个很好的保障,假如你的程序只需要几个函数,一个结构,你却花80%的时间来实现一套PERFECT的GC,无疑就是大材小用了。
3。你需要所有的类都有一个共同的基类吗?
依据我的设计,应该是不需要的。
4。你需要接口可以继承吗?
JAVA中,我非常需要,因为实现一个接口意味我将重写一次代码。为什么没有多继承呢?

以上皆为我一些浅见,如有错漏,欢迎批评指教,其他本人选择性失明。

刚刚看到tinyfool说的C++缺乏一个动态链接的标准的事情。

这说起来有点风马牛不相及了。即使有这个标准肯定跟C++本身也没有多大的关系,而是windows平台的事情了。

Java的Interface与COM的Interface还是有区别的,Java的Interface其实是一个tag,类似于标签性质的东东,并非虚拟类一类的东东。

win32平台本身是允许虚拟类放在动态库中继承使用的,但是标准我感觉难以制定,其实正是鉴于不同开发(语言)平台之间的呼叫方式的区别,MS才弄出来COM的safecall(是叫这个吧?),其实这也算是某种程度上的标准化吧。

有点扯远了 莫怪

是否应该考虑加入blog留言的编辑功能 :)

贴完发现标签有问题,最后一句是:
《HeadFirst.设计模式》中的部分解答

>>面向对象的本质就是让对象有多态性,把不同对象以同一特性来归组,统一处理。至于所谓继承、虚表、等等概念,只是实现的细节。

我完全不这么认为,OO的核心:(按重要性排序)

抽象,封装,多态,继承

个人感觉行为抽象和细节封装是OO的核心

其中多态和继承多被用来制作大型类库,类库这玩意还是个好东西,很多时候我们学习的不是语言,而是类库。

具体如何OO其实是有些准则的,如封装变化,多用组合,少用继承等(注意少用不是不用,这些都要具体问题具体分析)。

这些准则其实跟语言本身是否是OO关系不大,譬如常说的针对接口不针对实现,使用c或cpp都可以实做出来。

换言之,OO是我们看待事物的方式,具体OO的如何还要看OO的主体能力。

另外,对于一些三五十人参与大型工程(这个大型不是指难度,而是指规模),OO的目的不是让你的系统有多好,而是让你的系统不至于多坏。

p.s.我来回答下楼主的问题

>>你需要面向对象吗?
需要
>>你需要 GC 吗?
有无均可
>>你需要所有的类都有一个共同的基类吗?
这要看干什么
>>你需要接口可以继承吗?
需要
>>你为什么需要这些?
可以参看<Head.First.设计模式>中的部分解答。

在这里又看到了对C++语言本身的争论。作为C++的忠实使用者。在这里为C++平反,C++的最初设计是很符合当时的需求的,从80年代末到90年代中后期的流行,可以看出来。我想,在这里的读者,多数还是从C++出身的吧。

C++语言的特性是非常的多,所以对于学习和使用都是需要很长的时间。诸多的特性,使得使用者,在选择何种特性作为程序框架的基础的时候,就是一种考验。要做出最佳的选择,需要面向对象设计的知识和长期的积累的经验。所以,使用者在使用C++做项目的时候,失败一两次也不是不常见的。如果我没有记错的话,云风就有这样类似的经验:把一个用C++写的项目用C重写了一次。但是,这样的原因,大概是当初的基础框架没有设计好吧!所以,我猜测--云风大概对C++还是有点微词的。去年,有一场C/C++语言之争。最引人注目的应该是Linux之父对C++语言的贬低了。我听说(没有考证):他当初也想使用C++写操作系统,但是没有成功。

我喜欢C语言是喜欢它的精巧灵活,最重要的一个原因,是使用C写的代码,给人一种可以掌握全局的感觉,完全在掌握范围之内,即使有错,需要重构,也是在平面内重构。不像C++的类层次结构带来的时立体的重构,无疑,平面比空间更容易掌握。

当然,C++毕竟是一种在80年代发明的语言,与现在的java、C#是不能相比较的,更不要跟动态语言做比较。这样的比较明显是没有看到各个语言的适用范围。C++语言的各种设计优良的特性,还是被后来者吸收进去的。

关于,C++没有GC。GC在C++标准化的时候并不是没有。关于,为什么C++标准化没有加入GC,大家可以到google查查。但是,因为没有GC这一点,时常作为攻击C++的理由之一。十年或者是二十年前的内存价格和现在的内存价格作比较的话,应该都得到一个C++不加GC的理由。而java语言有GC是SUN公司战略需要的。

PS:云风这篇文章有鄙视C++的嫌疑:“C++ 提供了对面向对象的支持,但 C++ 所用的方法(虚表、继承、多重继承、虚继承、等等)只是一种在 C 已有的模型上,追加的一种高效的实现方式而已。” 这里的“只是”和“而已”。是否用得不是很恰当? -_-!!

PS:我赞同楼上一位仁兄说的:4、90%情况下都不需要严格意义上的类——拿那些C++特性当甜点吧;必须明白,虽然你写的东西以class开头,但那不是类。

在下最厌恶种类之一就是预言家。准确点说,是装B专家。
比如说,当初俺的前“白领”大领导就预言俺等蓝领们要被机器取代,要被饿死——其实我想他恐怕也很明白,国企不可能一直这样下去;将来要被饿死的,很可能是他们这些“白领”而不是真能干活的“蓝领”。但这并不妨碍他现在利用职权牟点私利,比如摆出一副救世主的模样,骗骗乃至欺压欺压刚出校门的GGMM。

近些年一直在网上鼓噪“软件蓝领论”的,恐怕多数都是这种“白领”。

同样,作为真正做技术的软件“蓝领”,他们的社交范围绝不可能仅限于国内;甚至可以说,不会到国际社区学习求助的,不可能保持长时间高效率的工作,更不可能保持长时间的技术领先——或者说,不是一个合格的“蓝领”。

这才是蓝领们真正意义上的朋友圈。

换言之:真正在踏踏实实做着技术的人,他的未来不是其他阴阳怪气的家伙所能预言的。

————————
另回jackyfire朋友:
面向对象的根本目的,是让程序设计及结构更简单、更可靠而不是相反。

老外有句话,原话忘了,大概意思就是说“比xxx(一件很难的事)更难的事情,就是让两个方法论专家闭嘴”。

方法论专家总是向我们承诺,只要照他的流程如何如何,你就一定能得到一个设计良好的系统。
但现实是:几乎任何两个方法论专家都无法取得共识。
这些家伙,某些时候简直和原教旨主义者一样讨厌;虽然很多情况下,他们确实能帮助我们。

有句话说的好,手里有把锤子,看到什么都是钉子。

扩充工具箱,别老用锤子;让方法论专家一个一个给出建议,然后把他们一脚踢开——这才是正确的做法。

回到C++等面向对象语言上,就是:如果高层抽象确实能归结于类,那么语言提供的便利不用白不用;就是语言没有提供支持,自己也要做一个出来。但如果抽象来抽象去,怎么看怎么都不对劲,那就别硬赶潮流。
到实现时,语言甜点只要能简化编码,同样是不用白不用;但假如用了这些甜点便自以为是面向对象,那就错的太离谱了。

= =!
封装应该是增加操作的粒度,如果封装使操作粒度变小,那么使用者的工作就会比不封装时更琐碎……

粒度差不多等于细度,细度影响复杂度,复杂度的结果就是难度,所以云风的表述应该是没有问题的。

有一个错别字 粒度==>难度

封装总是为了减少操作粒度,数
改为
封装总是为了减少操作难度,数

纠正一个概念。

面向对象和基于对象的区别不在于多态性。所基于的对象也同样可以具有多态性,比如FILE* 可以是一个磁盘文件也可以是控制台IO。

从字面理解,Object Oriented指的是程序的分析、设计、实现是围绕对象为中心来展开的,以对象来分解问题域并提供相应的实现机制。语言提供了实现对象所需要的机制(如:属性、方法、继承、多态等等)即称为面向对象的语言。

Object Base则是指使用对象,而不是设计和实现对象。

当一个人的技术提升到超越周围的人太多时,甚至谈论的不是同一个层面,他的道路便到头了。

他必须要换一个地方和另外一个同级别层次的人合作。

这样他原先的鹤立鸡群便变成了和周围一群人是一样的了,甚至被领导,也就是泯然众人亦。

可以说,要么你选错了工作,要么你选错了学习路径

再次提升,就是面对更激烈的竞争和跟高的要求

或许要从另一个平台的办事员开始做起和学起

就看你的突破能力了

或许你一直会呆在原地

形而上的不错(此处独立)

我估计你会宗教化或神学化或者哲学化(至少有一段时间)。

这是本人对你的预言

to ghost:
“一种设计境界或着说是一种思考方式、一种大局观的体现……”这个只是面向对象方法论的一个方面,即所谓的OOA,说它就是面向对像,或者面向对象就是它有点片面了。虚函数表、继承、多态性当然和面向对象的本质无关,他们是面向对象方法论指导下,对语言层面的一种实践。

@tinyfool

COM 允许一个实现继承多个接口,因为那是隐藏起来的实现的细节。但不允许一个接口继承多个 COM 接口。这个就是暴露在外的设计规范了。

所谓编程范式,设计模式乃至什么匈牙利命名法,驼峰命名法,注释,文档什么的不过是西方人以英语为思考模式弄出来的东西而已

程序是数据+逻辑,这个我们都知道

为了解放生产力,人类封装数据和逻辑,再将封装好的东西堆砌到一起。以前是用函数,然后有了类,又有了泛型,现在又流行函数式

我是觉得程序设计,用现实中存在的,最自然的方式去做就行了,大可不必设计必谈模式

ps:俺说的那个公司是个好几百开发人员的、据说过了cmm 3的中型企业;sz好多外包公司都在为它打工。

个人觉得,面向对象是一种设计境界或着说是一种思考方式、一种大局观的体现……

无论如何,它绝不是一种编程技法。

比如,可以用构造/析构函数来做“自动的成对工作”;但这只是依赖C++具体实现的一种运用技巧。
其他如虚函数表、继承乃至多态性,也都是如此。
类似的技巧可以解决很多问题;但它们和面向对象只是碰巧走到了一起,或者是面向对象语言提供的外在的便利。
根本意义上,这些东西和面向对象没有一星半点本质上的联系。


去年“误入”一家垃圾公司,他们仗着和某国有部门关系密切,没有竞争对手而瞎搞——自然,他们的代码完全可以作为最垃圾代码的最杰出代表来看。
也就是这些代码,让我想到了更多的东西,也看透了许多。

比如说,他们做的一个网上购物系统——倘若照我们的思路,大概应该分为如下3个模块:一个记帐模块,相当于出纳,负责处理点卡、充值、付款等操作;一个连接管理/认证模块,相当于接待员,负责session的维护以及错误信息的翻译等工作;一个UI模块,类似橱窗,以web方式展示商品。之后就只是一些进一步细化、扩充的工作了。
按这个设计思路走下去,该系统显然是非常灵活、容易扩充、容易重用的——总之,一切都很简单,没什么技术含量。

知道他们是怎么做的吗?
一个N多模块构成的巨大的蜘蛛网。
一个模块,负责用户接入和心跳,同时还要把用户提交的订单里的地址用订单模块的数据库里的信息翻译成商品代码,重新构造订单后再发给订单模块——老大,有这么玩的吗?
这个接入模块还有更倒霉呢(不好意思,负责实现这个倒霉模块的正是在下-_-|||):由于某种说不清道不明的原因,订单模块需要知道用户当前是否在线(如果不在线,接入模块要负责发短信通知用户登录:但这和订单模块有什么关系?);于是从接入模块又拉了条线过去,直接更新订单模块的数据库去了。
这样直接访问其他模块数据库的行为还有好多——他们用数据库存储程序状态。
它的点卡模块,不知道设计者吃了什么,居然搞了3个巨大的表玩联合查询,每个表都要出N多记录——这个N^2复杂度的BT原定要支持千万用户的,结果测试期刚插入1万条记录(不到1K用户),垮了:一次查询就要N分钟;一次统计要7、8小时(俺就是负责调查原因的倒霉蛋之一;轻松找出了原因,却被告知这几个表被很多模块共用,改不了了!)
最搞笑的还是它的日志审计模块:为了分析每天预计数十G的日志并入库,这个模块让很多类紧密团结在以工厂模式为核心的、以观察者模式为指导思想的一锅粥大家庭里(此外,他还用了包括单建在内的NN个设计模式——光这点就比俺牛。设计模式俺看得快,忘得更快;以后说不定顺手似是而非的用出来时还以为是自己的发明,绝不可能做到如此的原汁原味)。
等整理出主干一看,它同时启动20个线程读入20个日志文件,全部读完后到达第一个同步点;然后,同时开20个线程分析日志,全部分析完到达第二个同步点;于是同时开20个线程通过网络更新到数据库(全部更新结束为第三个同步点);然后,重复。
嗯,想象下开20个线程暂不执行,然后一声令下,看它们争抢那点可怜巴巴的资源严重影响效率的可笑景象吧;更可笑的是,争完了,抢完了,刚才的热门资源就被晾在一边,看20个强盗去抢另一个热门——倘若磁盘和网络有思想,想必会发出很多极有哲理性的感叹。

总之,这个系统就是这样一个蜘蛛网构成的模块构成的蜘蛛网;时不时还要在模块间走上几条飞线,组成个连设计者都有点不好意思提的地下暗网。
俺当时的顶头上司很有正义感的告诉我们:他们软件白领花了好大的力气才能把这个蜘蛛网理清,然后俺们这些软件蓝领们才能把一条条的线织出来。然后语重心长地告诫我们,“你们这些照图织网的家伙很快就会被机器替代”。

好吧,我的意思就是:
1、某种意义上,C++(以及设计模式乃至任何面向对象语言)很垃圾。因为它很容易造就如上所述的那些走火入魔者——不幸的是,他们往往还掌握着话语权。
2、依现实做出设计,为目标选择语言;若非必要,放弃任何“高级”特性乃至任何“特性”——C++很好,但我们先要学会放弃。
3、设计类是极高难度的现实工作;评判一个类的好坏都至少需要你先彻底搞明白什么是“正交分解”——至于搞明白设计目标及应用场合,那是基础中的基础。
4、90%情况下都不需要严格意义上的类——拿那些C++特性当甜点吧;必须明白,虽然你写的东西以class开头,但那不是类。
5、C++给的好东西太多了,以至于如何克制自己不去滥用都成了学问——正如云风这篇文章。
6、unix的泛文件设计是真正面向对象的,虽然他们用C;C基础库的QSort也已经有了点面向对象的味道,虽然它用了void *;而前面说的那个项目则连结构化的程度都没做到——虽然他们用的是以设计模式粘连的C++“类”。
7、很多时候,你真的不知道和你说话的是什么。有的人,和他多说一个字都是浪费。
8、如果哪位读者误入了类似的垃圾公司,哪怕像我一样还被压着一个月的工资——早点走吧。等被改造成笨蛋就不好玩了^_^


很同意对于面向对象的看法,不过俺对COM不知,不发意见。不过在C语言里面,面向对象的开发已经流行很多年了,而且也有各种不同的方式.面向对象的实现细节的确不是那么重要了,不过现在有个思想的确已经很深入人心了,就是面向接口编程而尽量不是去通过继承实现来复用。

不过我个人不太同意不是面向对象的程序不需要GC, GC应该并不绑定对象这个概念,虽然目前的大部分实现都是如此。GC本身,不考虑所谓便利性,很大程度是为了隐藏内存这个概念,一个比较“高级”的语言,无论它是不是“面向对象”的,如果他有内存管理,而这个内存管理并不希望用户能“看到”的话,就可能需要GC.

面向对象只是一个所谓的编程范型,把东西组织为对象,也会出现所谓的对象悖论,人家本没有速度,完全就是你这个观测者强加的。不过现在流行的语言都是带有OO编程范型的支持的。不过随着其他范型比如FP的重新流行,OO不再是救命稻草了,看上去和其他范型混合的趋势越来越大。

个人意见!

以前我也认为C++ 对面向对象的支持的实现本身就是面向对象的本质。现在,也不再如此觉得,面向对象应该是一种看待事物的角度罢了,语言只是客观的一种实现工具,与人怎么去看待、思考问题毫无关系。

最近也在想,“你需要所有的类都有一个共同的基类吗?你需要接口可以继承吗?你为什么需要这些?”这些问题,感谢云风分享这些思考,学习很多。

对文中的思想我没有太大的意见,有几个细节商榷下
1 这个其实是小问题,我觉得你说的基于对象跟一般概念说的基于对象不太一样,这不是啥大问题,我感觉一般说的基于对象更像是说利用一个面向对象的程序库去做程序.或者说,我觉得一般概念的基于对象,可以说是使用对象,而不是创造新对象.我觉得你用的基于对象这个词,比较像用对象这个概念来思考问题解决问题.

2 如果我没有记错的话,Com是可以接口多继承的.也许是咱们理解的差异,但是我确实记得是可以的.C++的一个备受争议的点就是多继承,Com对此的策略是实现不能多继承,但是接口可以.Java也是如是.我觉得这是一个思路的进步,这个比较符合你的文章主题,就是实现的继承其实没有接口的继承那么重要.

3 我对Com的认识在于,C++缺乏一个动态链接的标准,加上支持多继承,二进制层面无法提供一致性.比如在win平台下用C用不同的开发工具编写同一个函数,或者是不同函数的版本,只要函数名,参数和参数压栈顺序相同,那么DLL的接口一致性是可以保证的.但是由于前面说的C++缺乏一个动态链接的标准,加上支持多继承,如果你提供的接口是类,或者类的一个方法,接口一致性就无法保证.而保证接口一致性的方法其实不难,实际上就是接口要用纯虚基类.其实java的interface关键字跟这个也是一脉相承的,只要是纯虚基类,其实就可以保证二进制的一致性.所以在我看来COM的最核心就在于动态链接+纯虚基类继承,也就是接口继承.AddRef Release是个半自动化的内存管理,QueryInterface是一个动态的接口查询,他们都是辅助,不是核心内容.

最近也在看设计模式的东西

Post a comment

非这个主题相关的留言请到:留言本