话又说回来,二进制接口的变化也不是什么大问题,比如你用 C++ 写了一个 OS,
提供了 template/OO 的 C++-only 的 API,那么每当推出新版本 OS 的时候,只
需在说明书里添加一句"请联系软件供应商确保支持新版本 OS"即可,甚至还能搞
个 "Designed for MyOS" 认证,捞上一笔,何乐而不为呢。
在这方面,无数的 Linux/*BSD 发行版已经实践了多年:操作系统本身和应用程序
都是一起发布的,使用同一版本的编译器,也就不存在二进制兼容性问题。如果你
想用不被发行商支持的软件,那么唯一的途径就是自己编译,如果是闭源软件,那
么只有去找开发商抱怨了。
在 2007-09-16日的 13:15 +0800,pongba写道:
> 主要是说OO这个高阶特性。C++/D都支持OO,但同时C++和D的模块又都是二进制
> 复用的(总不能要求每个机器都安装编译器然后发布源代码吧),这就构成了矛
> 盾,什么矛盾呢?矛盾在于二进制复用的本质导致了OO技术在二进制边界上必须
> 让步。如果跨二进制边界即使传输一个接口指针的话,那么后面就再也不能动这
> 个该死的接口了,就连加个成员函数都不成。跟别说减,或者分裂接口了。最违
> 反直觉的就是加成员函数也不成。
>
> 另一方面,真正高阶的语言,像ruby这种脚本语言,抛弃二进制复用,那么这个
> 矛盾立即解决了。再加上强大的火星人类型系统,就算一个函数所依赖的对象整
> 个变掉了加了成员数据了加了成员函数了又减了成员函数了或者改变成员数据排
> 列顺序了加了基类了减了基类了,管它的,只要这个函数所依赖的那些个成员函
我最近用 D 写的一个服务器框架, 用得多的是 GP (反正编译很快), mixin; 继承
用得很少, 只有一个类有两次继承, 其中一层是看到代码量比较大, 将一些逻辑上
相对独立的东西抽了出去, 另外一层是为了可以 copy tango 的 各种 poll
selector代码来用(poll, select, epoll, 以后可能有 kqueue), 否则用 GP 更合适.
这个框架完毕之后, 对外也是不会暴露这些内部关系的, 写一个 struct 出来, 里
面放上delegate, 给外面做接口, 这就和 com 差不多了, 似乎也很简单. C++ 的
member function 不容易完成 delegate 的任务, 不好用这个方法, D 倒没有问题.
现在的我的代码更倾向于所谓的 object based, 而不是 object oriented 了.
搞得太 OO, 之前讨论过的开销就不说了, 碰到线程同步这个问题, 就更多罗嗦,
如果对象和类的关系复杂, 程序的当前状态需要多个对象才能共同表达出来, 函数
调用链复杂, 再加上临界区跟随 OO 而细化, 那人肉分析会不会死锁, 简直就成为
不可能的任务了.
我就写过一个这样的程序, 到最后, 我也无法搞清楚我的程序有没有同步问题, 大
量测试的时候, 有很低的几率会出现一些问题, 但是不知道具体缘故, 因为调用链
太复杂, 程序的状态分布到太多对象中去了.
反倒是, 如果用过程式语言写, 数据就是在那里了, 要访问什么, 加哪个锁, 很清
晰, 要调试应该也会简单不少.
OO 是用增加数据之间的复杂性来换取操作之间的抽象和内聚, OO 过了问题很大.
云风的看法是过度设计比代码冗余危害更大一些. 我的看法在云风的基础上还有一
点, 代码冗余问题, 靠人力堆上去是容易解决的, 但是设计太复杂带来的问题, 人
力堆上去都没有用处.
如果程序中临界区种类多, OO 还更不要太复杂了, 否则重犯我翻船错误的几率估
计不小.
pongba 写道:
> 主要是说OO这个高阶特性。C++/D都支持OO,但同时C++和D的模块又都是二进制
> 复用的(总不能要求每个机器都安装编译器然后发布源代码吧),这就构成了矛
> 盾,什么矛盾呢?矛盾在于二进制复用的本质导致了OO技术在二进制边界上必须
> 让步。如果跨二进制边界即使传输一个接口指针的话,那么后面就再也不能动这
> 个该死的接口了,就连加个成员函数都不成。跟别说减,或者分裂接口了。最违
> 反直觉的就是加成员函数也不成。
>
> 另一方面,真正高阶的语言,像ruby这种脚本语言,抛弃二进制复用,那么这个
> 矛盾立即解决了。再加上强大的火星人类型系统,就算一个函数所依赖的对象整
> 个变掉了加了成员数据了加了成员函数了又减了成员函数了或者改变成员数据排
> 列顺序了加了基类了减了基类了,管它的,只要这个函数所依赖的那些个成员函
> 数都还在,就没问题,就能把那个对象所在的模块给换掉。云风一语道破天机,
OO 真是这么重要吗 ?
我最近用 D 写的一个服务器框架, 用得多的是 GP (反正编译很快), mixin; 继承
用得很少, 只有一个类有两次继承, 其中一层是看到代码量比较大, 将一些逻辑上
相对独立的东西抽了出去, 另外一层是为了可以 copy tango 的 各种 poll
selector代码来用(poll, select, epoll, 以后可能有 kqueue), 否则用 GP 更合适.
这个框架完毕之后, 对外也是不会暴露这些内部关系的, 写一个 struct 出来, 里
面放上delegate, 给外面做接口, 这就和 com 差不多了, 似乎也很简单. C++ 的
member function 不容易完成 delegate 的任务, 不好用这个方法, D 倒没有问题.
现在的我的代码更倾向于所谓的 object based, 而不是 object oriented 了.
搞得太 OO, 之前讨论过的开销就不说了, 碰到线程同步这个问题, 就更多罗嗦,
如果对象和类的关系复杂, 程序的当前状态需要多个对象才能共同表达出来, 函数
调用链复杂, 再加上临界区跟随 OO 而细化, 那人肉分析会不会死锁, 简直就成为
不可能的任务了.
我就写过一个这样的程序, 到最后, 我也无法搞清楚我的程序有没有同步问题, 大
量测试的时候, 有很低的几率会出现一些问题, 但是不知道具体缘故, 因为调用链
太复杂, 程序的状态分布到太多对象中去了.
反倒是, 如果用过程式语言写, 数据就是在那里了, 要访问什么, 加哪个锁, 很清
晰, 要调试应该也会简单不少.
OO 是用增加数据之间的复杂性来换取操作之间的抽象和内聚, OO 过了问题很大.
云风的看法是过度设计比代码冗余危害更大一些. 我的看法在云风的基础上还有一
点, 代码冗余问题, 靠人力堆上去是容易解决的, 但是设计太复杂带来的问题, 人
力堆上去都没有用处.
如果程序中临界区种类多, OO 还更不要太复杂了, 否则重犯我翻船错误的几率估
计不小.
On 9/16/07, red...@gmail.com <red...@gmail.com> wrote:OO 真是这么重要吗 ?
啊哈:) 偶可没说OO有那么重要啊:) 其实只要OO有用,这个问题都可以讨论的。
redsea认为GP和OO的职责有交集吗?如果有的话,GP跟OO这两种抽象机制哪个更好呢?(取决于哪种对"好"的定义)。
这 个框架完毕之后, 对外也是不会暴露这些内部关系的, 写一个 struct 出来, 里
面放上delegate, 给外面做接口, 这就和 com 差不多了, 似乎也很简单. C++ 的
member function 不容易完成 delegate 的任务, 不好用这个方法, D 倒没有问题.
现在的我的代码更倾向于所谓的 object based, 而不是 object oriented 了.
OB,就是OB。本来人的思维模式也是先认识实体再抽出共性的。每写一个concrete class就要考虑抽象,烦不胜烦,还不如直接写具体类,然后辅以GP解耦合以避开过度依赖的问题,以后,如果实在必要的话,再考虑用interface 和继承
恩, 我也是这样, 然后会发现, 可以很少动用到 OO.
你说的也很有道理.尤其是,OO一旦抽象抽错了,依赖已经造成,大错就很难挽回了。我觉得这个风险才是最重要的弊端。而过程式的抽象逼着你去只依赖必须依赖的东西,接口也很 紧凑,耦合更小,不像interface,一依赖就依赖一个整体。另外,我还没做过non-trivial的OO设计,也就是看看一些Bob的《敏捷软件 开发:原则模式与实践》和Meyer的OOSC等之类的书,再加上一些思想实验而已,所以可能在方家看来纯属扯淡 :P