锁定老帖子 主题:面向对象之弊,面向过程之优
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-08-06
面向对象本来就没考虑到代码量,他是个设计和思路的问题。思路是面向对象的,怎么写都无所谓,思路是面向过程的,怎么的都是面向过程的。楼主的认识也它浮浅了啊。
数据和算法可以玻璃,思路和代码实现也是可以剥离的啊。 |
|
返回顶楼 | |
发表时间:2010-08-06
各有优缺点吧
个人认为面向对象相对于面向过程的最大优点在于更大限度的代码复用 而面向过程相对于面向对象的最大优点在于节省空间和时间 |
|
返回顶楼 | |
发表时间:2010-08-07
liudun 写道 我想多看看优秀的开源代码是有益于理解OOP的。
工作中接触的同事们,很多都有搞C、C++经历的,所以它们写的java代码都是贫血对象——就是说领域对象本省总是没有任何逻辑,逻辑都放到**Manager、**Service里面去了。这没办法,‘一切皆对象’的思想并没有普及。到处都是面向过程的java代码。 我是电信行业的,有个网管规范叫TMF814,针对专属网的corba接口定义。 这个接口的设计特点就是典型的“所以它们写的java代码都是贫血对象——就是说领域对象本省总是没有任何逻辑,逻辑都放到**Manager、**Service里面去了”。而制定这些标准的都是牛人,不是没深刻理解面向对象思想的人。 我编写网管软件,一开始对象模型采取兼容814的corba对象,同时将相当于部分Manager,Service的逻辑归入到领域对象,但随着越往后写越觉得规范定义的方式是合理的。领域对象承载了过多的逻辑,引入了过度对其他对象的引用,领域对象的膨胀发觉时及其危险的,很容易就带来代码的不可控和难以重构。 举例来说对象A,B,C在作为设备对象存储设备信息,一种情况下,需要获得一个List<C>,而这个List<C>是由List<A>和List<B>共同决定的,这种情况下引入Manager、和Service对象就是顺理成章的事情了 设备对象A,B,C往往是相互关联相互作用的,而网管里面同时涉及大量这种互相关联的逻辑,最好的方式还是应该都放入领域对象之外的控制逻辑中,就成了Manager、和Service对象,而看看Manager、和Service对象其实严格意义是说白了就是PO函数的作用域封装。 实际工作中感觉OO解决的主要问题集中在几个方面: 1.接口契约 2.如楼主所说的作用域的划定和封装 3.RTTI,这个已经不是严格意义上属于OO语言层面的内容,但越偏向OO的语言,这个东西作用范围越大。JAVA几乎所有的流行框架实际都是建立在这个基础之上的。不过我是觉得这个是可读和调试的天敌,用编码的复杂性带来了运行时的灵活性。但同时也将问题从编译器带到了运行期。C++在RTTI方面是先天不良,没有标准,C++只能各显神通的人肉级别做RTTI比如MFC,不是因为这个相信java的很多框架设计思想是很容易复制到c++的。RTTI大大简化了分布式的实现,这也是java在应用广度上能超越c++的重要原因 OO感觉还是适合主要放在初期的领域模型设计当中,并且对于抽象和继承尤其要谨慎,现在发觉不合理的代码抽象远比代码冗余危险,后者顶多带来重构困难,前者基本上让你抓狂到有推到重写的冲动。 至于所谓的面向对象更接近人的思维模式和面向对象更适合解决复杂问题,觉得有点扯 人的思维永远是基于语言的,学的汉语就是汉语思维,英文就是英文思维,但不管什么思维,描述一个问题语法都是主谓宾,定状定补,这就是典型的面向过程的思维。 至于面向对象更适合解决复杂问题,确切的说应该是面向对象更适合解决庞杂的问题,将业务模型和实现逻辑拆分化整为零。实际面向过程同样有这个能力,只是天然的缺乏多态继承的全面向过程语言要做很多额外的工作,拆分成本要高很多,并且封装性和作用域也很难保证。 谈到复杂性世界上能有多少软件面向的业务能比操作系统或者类似ORACLE的CBO更复杂。 |
|
返回顶楼 | |
发表时间:2010-08-09
ppgunjack 写道 liudun 写道 我想多看看优秀的开源代码是有益于理解OOP的。
工作中接触的同事们,很多都有搞C、C++经历的,所以它们写的java代码都是贫血对象——就是说领域对象本省总是没有任何逻辑,逻辑都放到**Manager、**Service里面去了。这没办法,‘一切皆对象’的思想并没有普及。到处都是面向过程的java代码。 我是电信行业的,有个网管规范叫TMF814,针对专属网的corba接口定义。 这个接口的设计特点就是典型的“所以它们写的java代码都是贫血对象——就是说领域对象本省总是没有任何逻辑,逻辑都放到**Manager、**Service里面去了”。而制定这些标准的都是牛人,不是没深刻理解面向对象思想的人。 我编写网管软件,一开始对象模型采取兼容814的corba对象,同时将相当于部分Manager,Service的逻辑归入到领域对象,但随着越往后写越觉得规范定义的方式是合理的。领域对象承载了过多的逻辑,引入了过度对其他对象的引用,领域对象的膨胀发觉时及其危险的,很容易就带来代码的不可控和难以重构。 举例来说对象A,B,C在作为设备对象存储设备信息,一种情况下,需要获得一个List<C>,而这个List<C>是由List<A>和List<B>共同决定的,这种情况下引入Manager、和Service对象就是顺理成章的事情了 设备对象A,B,C往往是相互关联相互作用的,而网管里面同时涉及大量这种互相关联的逻辑,最好的方式还是应该都放入领域对象之外的控制逻辑中,就成了Manager、和Service对象,而看看Manager、和Service对象其实严格意义是说白了就是PO函数的作用域封装。 实际工作中感觉OO解决的主要问题集中在几个方面: 1.接口契约 2.如楼主所说的作用域的划定和封装 3.RTTI,这个已经不是严格意义上属于OO语言层面的内容,但越偏向OO的语言,这个东西作用范围越大。JAVA几乎所有的流行框架实际都是建立在这个基础之上的。不过我是觉得这个是可读和调试的天敌,用编码的复杂性带来了运行时的灵活性。但同时也将问题从编译器带到了运行期。C++在RTTI方面是先天不良,没有标准,C++只能各显神通的人肉级别做RTTI比如MFC,不是因为这个相信java的很多框架设计思想是很容易复制到c++的。RTTI大大简化了分布式的实现,这也是java在应用广度上能超越c++的重要原因 OO感觉还是适合主要放在初期的领域模型设计当中,并且对于抽象和继承尤其要谨慎,现在发觉不合理的代码抽象远比代码冗余危险,后者顶多带来重构困难,前者基本上让你抓狂到有推到重写的冲动。 至于所谓的面向对象更接近人的思维模式和面向对象更适合解决复杂问题,觉得有点扯 人的思维永远是基于语言的,学的汉语就是汉语思维,英文就是英文思维,但不管什么思维,描述一个问题语法都是主谓宾,定状定补,这就是典型的面向过程的思维。 至于面向对象更适合解决复杂问题,确切的说应该是面向对象更适合解决庞杂的问题,将业务模型和实现逻辑拆分化整为零。实际面向过程同样有这个能力,只是天然的缺乏多态继承的全面向过程语言要做很多额外的工作,拆分成本要高很多,并且封装性和作用域也很难保证。 谈到复杂性世界上能有多少软件面向的业务能比操作系统或者类似ORACLE的CBO更复杂。 1. corba是远程调用。其中的参数应该是贫血对象。因为远程主机上的代码版本有时不是你能控制的。 2. 设备信息用list来表示,就不太OO了。不定义个实体对象,也至少用Map啊。 3. cpp放弃rtti也许是为了性能考虑。因为如果失去这一点,cpp的竞争力大大减弱。cpp是想既要有c的性能,又有oo语言的特性。 4. cbo是否复杂我不知道。但做同样一个产品,分别选用cpp和其他语言实现就能比较出结论了。 5. 很多人反对OO其实是没掌握好OO。 比如,举个例子。Integer对象。那么Integer a=1,b=2; 如果是非贫血对象要做加法就是:c=a.plus(b); 如果是贫血对象就是:c=IntegerManager.plus(a,b); 哪个好是显而易见的。如果你支持PO,那么基本上就选择了static关键词。 问题是在涉及数据库/分布式/并发的现实环境下,要进行ddd就不是这么简单了。 |
|
返回顶楼 | |
发表时间:2010-08-10
不是参数是贫血对象,而是领域模型是贫血对象,主控逻辑所在的对象则主要是方法包装
两端的版本都是由idl决定的,是不需要其他方式的控制 本来现实世界很多问题并不适合OO。 STL的算法的设计理念就是典型的例子, 不是设备信息用list来表示,而是设备集合信息用list表示。这个list再封装成一个对象没啥意义,这种应用其实可以参考STL。目的就是要集合B和集合C通过运算生成集合A。 cpp放弃rtti是先天缺陷,不是性能,它是静态语言且不是托管语言,没有在语言层面支持,在哪个没标准的年代更没可能依靠宏或者库统一rtti的实现 “ 如果是非贫血对象要做加法就是:c=a.plus(b); 如果是贫血对象就是:c=IntegerManager.plus(a,b); ” 这个例子的结论我认为正好相反,我有两个问题: 1.plus为何要属于Integer对象。如果今后的逻辑我需要引入更多的计算方法是否应该重构Integer,java的编译方式我不太确定,但如果是c++则不论你是否引入接口,则至少必然导致所有使用Integer头文件的代码都要重编译 2.Integer对象作为数据容器对象,引入了其对象本身,这个还没彰显问题。假设a,b如果是不同class呢? a所属的class毫无疑问被b给侵入了。那么考虑c=IntegerManager.plus(a,b);其实IntegerManager承接了a和b的桥梁,把关联依赖集中放在了IntegerManager里面。 你觉得处理这个问题的话那种方式更好? 其实table A, table B, table relationAB就是这种模式 其实包括工厂模式和spring作为组件粘合剂我觉得他们更多的思维本质还是是面向过程的只是用xml和接口给美化了而让人忽略了 而且java这样的实际面向过程的工具类少吗,毕竟有些问题只适合这么处理 |
|
返回顶楼 | |
发表时间:2010-08-10
有意思的是,我在写代码的时候,真的最早就是按照c=a.plus(b);来写的
大概的样子是 A a; B b; C c; c=a.parse(b) 类似这个样子,不过越往后,越觉得不合理,就演变变成了 c=Parser.parse(a,b), 代码一半是前面的实现,一半是后面的实现,很滑稽 其实思路很容易理解: 1.a需要知道b吗,不需要我干嘛要A的class引入B。 2.c需要知道a或者b嘛,可以说需要可以说不需要。那么只有两条路:A,B作为构造参数或者第三方处理,当c是个list或者不是自己能控制代码的类的时候,结果就已经很明确了,路只有一条 |
|
返回顶楼 | |
发表时间:2010-08-10
ppgunjack 写道 有意思的是,我在写代码的时候,真的最早就是按照c=a.plus(b);来写的
大概的样子是 A a; B b; C c; c=a.parse(b) 类似这个样子,不过越往后,越觉得不合理,就演变变成了 c=Parser.parse(a,b), 代码一半是前面的实现,一半是后面的实现,很滑稽 其实思路很容易理解: 1.a需要知道b吗,不需要我干嘛要A的class引入B。 2.c需要知道a或者b嘛,可以说需要可以说不需要。那么只有两条路:A,B作为构造参数或者第三方处理,当c是个list或者不是自己能控制代码的类的时候,结果就已经很明确了,路只有一条 建议看看ruby是怎么做加法的。 另外,职责分散了好做,还是把职责统一到一个Manager里好维护? 仅仅ABC三个类就有8种相加的组合,如果是10个类呢?你的Manager准备写多少逻辑?是指数级别的吧。 相反,如果各自来处理加法,则A只要处理:加A、加B、加C三种逻辑,是线性的。每个类自己负责自己的事,世界才有规律。 扯远一点,就是大-中-央-集-权好,还是社会自治好。 |
|
返回顶楼 | |
发表时间:2010-08-10
依赖很麻烦,甚至可以说是一切麻烦的根源,数据库范式解决的就是依赖,接口解决的还是依赖
你说cs好还是bs好,哪个容易维护 计算机从最早的终端-主机转到cs又回到类似终端-主机的bs架构 你认为plus是class A的职责吗,如果是放进去ok,不是就不应该放 人就是人,人自己能干活 但你可以看看自己干的多少活不是别人让你干的,也只是作为个参数而已被manager在处理 |
|
返回顶楼 | |
发表时间:2010-08-12
ppgunjack 写道 依赖很麻烦,甚至可以说是一切麻烦的根源,数据库范式解决的就是依赖,接口解决的还是依赖
你说cs好还是bs好,哪个容易维护 计算机从最早的终端-主机转到cs又回到类似终端-主机的bs架构 你认为plus是class A的职责吗,如果是放进去ok,不是就不应该放 人就是人,人自己能干活 但你可以看看自己干的多少活不是别人让你干的,也只是作为个参数而已被manager在处理 1 关于“终端-主机转到cs又回到类似终端-主机的bs架构”这个问题,我觉得是当年最初为了利用大型主机的资源,后来是c/s是因为没了大型主机,也没有浏览器这样的标准客户端,再后来b/s是为了方便发布.客户端的胖瘦会一直演变下去。 2 你的职责还是属于你的,你的manager不会替你干活,他下指令给你让你干活。如果你只是个不会干活的参数(headcount),他估计早就废了你。 |
|
返回顶楼 | |
发表时间:2010-08-12
ppgunjack 写道 liudun 写道 我想多看看优秀的开源代码是有益于理解OOP的。
工作中接触的同事们,很多都有搞C、C++经历的,所以它们写的java代码都是贫血对象——就是说领域对象本省总是没有任何逻辑,逻辑都放到**Manager、**Service里面去了。这没办法,‘一切皆对象’的思想并没有普及。到处都是面向过程的java代码。 我是电信行业的,有个网管规范叫TMF814,针对专属网的corba接口定义。 这个接口的设计特点就是典型的“所以它们写的java代码都是贫血对象——就是说领域对象本省总是没有任何逻辑,逻辑都放到**Manager、**Service里面去了”。而制定这些标准的都是牛人,不是没深刻理解面向对象思想的人。 我编写网管软件,一开始对象模型采取兼容814的corba对象,同时将相当于部分Manager,Service的逻辑归入到领域对象,但随着越往后写越觉得规范定义的方式是合理的。领域对象承载了过多的逻辑,引入了过度对其他对象的引用,领域对象的膨胀发觉时及其危险的,很容易就带来代码的不可控和难以重构。 举例来说对象A,B,C在作为设备对象存储设备信息,一种情况下,需要获得一个List<C>,而这个List<C>是由List<A>和List<B>共同决定的,这种情况下引入Manager、和Service对象就是顺理成章的事情了 设备对象A,B,C往往是相互关联相互作用的,而网管里面同时涉及大量这种互相关联的逻辑,最好的方式还是应该都放入领域对象之外的控制逻辑中,就成了Manager、和Service对象,而看看Manager、和Service对象其实严格意义是说白了就是PO函数的作用域封装。 实际工作中感觉OO解决的主要问题集中在几个方面: 1.接口契约 2.如楼主所说的作用域的划定和封装 3.RTTI,这个已经不是严格意义上属于OO语言层面的内容,但越偏向OO的语言,这个东西作用范围越大。JAVA几乎所有的流行框架实际都是建立在这个基础之上的。不过我是觉得这个是可读和调试的天敌,用编码的复杂性带来了运行时的灵活性。但同时也将问题从编译器带到了运行期。C++在RTTI方面是先天不良,没有标准,C++只能各显神通的人肉级别做RTTI比如MFC,不是因为这个相信java的很多框架设计思想是很容易复制到c++的。RTTI大大简化了分布式的实现,这也是java在应用广度上能超越c++的重要原因 OO感觉还是适合主要放在初期的领域模型设计当中,并且对于抽象和继承尤其要谨慎,现在发觉不合理的代码抽象远比代码冗余危险,后者顶多带来重构困难,前者基本上让你抓狂到有推到重写的冲动。 至于所谓的面向对象更接近人的思维模式和面向对象更适合解决复杂问题,觉得有点扯 人的思维永远是基于语言的,学的汉语就是汉语思维,英文就是英文思维,但不管什么思维,描述一个问题语法都是主谓宾,定状定补,这就是典型的面向过程的思维。 至于面向对象更适合解决复杂问题,确切的说应该是面向对象更适合解决庞杂的问题,将业务模型和实现逻辑拆分化整为零。实际面向过程同样有这个能力,只是天然的缺乏多态继承的全面向过程语言要做很多额外的工作,拆分成本要高很多,并且封装性和作用域也很难保证。 谈到复杂性世界上能有多少软件面向的业务能比操作系统或者类似ORACLE的CBO更复杂。 C++最早是 c with class。后期引入了template 等概念。严格来说不具有完整oop的特性。java的设计也不能照搬到cpp上去。 现在我手头的项目,数据的定义通过ice来制定,server 用cpp ,client用 其他语言。ice制定的其实就是所谓的规范。这种复合的环境下,使用贫血对象是合理的。 |
|
返回顶楼 | |