梁 兄

【Unix C/C++, VC++, Java】 【QQ:704839634】【QQ群:44633982, 26678700】 【应聘:主管,深圳,x0万+】

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  80 Posts :: 5 Stories :: 536 Comments :: 0 Trackbacks
         在c++和java世界里,面向对象设计是老话题,基本上看过一两本书,做过一点开发的人,
你问他关于面向对象设计中的继承、组合、聚合,他肯定能回答出来,也会写基类、派生类、
java中的接口等等.
        但实际情况是不是这样呢?在真实的系统开发中,他们设计出来的类层次,真的理解透了
面向对象设计吗,特别是继承、组合、聚合之间的区别吗?前段时间分析了下以前写的一个模块,
让人大跌眼睛,看来实际项目系统中的设计没那么简单。
        为什么看书时很多人都很明白,一到实际开发就乱套了。你看看书上的例子,每次不是拿
图形来举例,就是拿动物来举例。比如用动物来说明继承关系:
                  Animal(动物)
                          |
             ------------------
             |                         |
            Cat(猫)           Dog(狗)
       大家基本上都能明白,动物是抽象的概念,猫和狗是动物的一种,他们都有年龄、体重这些
共同的属性,都有吃东西这个行为, 我们自然知道把这些共同的东西体现在Animal类里.
       拿这些很明白的例子来分析,大家都很容易搞清楚三种情况:是一种(继承),有一个(组合),
使用了(聚合). 真正的系统开发中,很难区分的清楚,比如我们做移动电信系统,其中就有一个
数据同步模块,管理我们的内部系统和移动boss系统之间的数据同步. 数据同步分为开户同步、
销户同步等等.
                 DataSync(基类)
                         |
             --------------------
             |                            |
         OrderSync              CancelSync
        这些数据同步最后采用HTTP+SOAP协议发送给对方,因为SOAP打包是和具体参数以及XML schema
定义相关的,是各个子类特有的; 然而对HTTP的打包和发送,这块代码是大家共有的,因此实现的
人就把这块代码移动到基类DataSync来实现,然后采用模板方法设计模式来获取不同的HTTP body
内容。
         看来一切都正常,是个好继承体系. 随着项目发展,现在要添加对某平台的数据同步,但是
它不采用HTTP协议来通讯,采用直接在TCP层上跑自己的自定义格式。因为以前把发送那部分代码
放到了基类里,现在这部分代码变化了,为了继续使用模板方法设计模式这个已经成型的框架,
结果只有修改基类的发送部分代码了。
         这个解决方案造成我们引进一个新需求时,需要修改我们的基类!细细分析了<<java与模式>>
的第二部分: 面向对象的设计原则,就知道这个设计违反了“开-闭”原则。这个原则说的是,一个
软件实体应当对扩展开放,对修改关闭; 在设计一个模块的时候,应当使这个模块可以在不被修改
的前提下被扩展。
        为什么会违反这一基本原则呢? 原因就是理解错了继承、组合、聚合在这一实际问题上的关系,
我们数据同步模块对上层客户模块来说,上层并不关心你采用什么协议发送数据,只管把该给你的
数据给你提供完备; 从数据同步模块本身来说,它的部分子类是采用了HTTP协议来发送数据,将来
的一些新加进来的子类,可能采用其它协议来发送数据,所以这里是一种聚合的关系。
        如果早期我们就正确发现这一关系,把HTTP打包发送做成一个工具类,子类仅仅通过聚合的方式
来引用它,基类并不写死这块代码,那么我们现在新加入对某平台的数据同步,并不会造成修改基
类的现象,只是把新功能添加进去而已,这不就满足了对扩展开放、对修改关闭的“开-闭”原则吗。
        从这一实际现象看出,很多人虽然拿着高薪,做着公司的高级程序员,其实并不都是很好理解了
面向对象设计的各个方面要点。为什么他们还是很厉害,拿高薪呢?一个是他们是老员工,对业务
十分熟悉,掌握着公司的业务和技术秘密, 不管设计的如何垃圾,他们总能把功能实现出来; 第二
就是老板根本就不看代码,也看不懂代码,只管最后功能实现就是了,他根本无法理解这种设计错误
造成的软件可扩展性、可维护性、可复用性的问题,增加了工作量,以为全部是业务逻辑复杂性造成
的。
      关于面向对象的设计原则:“开-闭”原则、里氏代换原则、依赖倒转原则、接口隔离原则、组合
/聚合复用原则、迪米特法则, 请细细阅读《java与模式》第二部分,不管是c++程序员还是java
程序员. 理解了这一部分,才能把握全书,才能理解设计模式解决了什么,这是《设计模式》那本书
没有提到的关键点!
       现在很多C++程序员,依然写着带类的C程序,C++因为兼容C,造成了拥有4种设计并存:结构化
设计、基于对象设计、面向对象设计、泛型设计。在这么复杂的环境里,偏偏这些程序员不学习,
很少看c++之父的《c++程序设计语言》、著名的《C++ primer》、经典的《Effective C++》和姊妹
篇《More Effective C++》、四巨头《设计模式》等等关于设计和编程的经典著作。
       而java程序员呢,常常发现没看过《java编程思想》、《java与模式》、《重构》、《深入java
虚拟机》等等,就知道摆弄structs/hibernate/spring/jboss/weblogic这些框架,还不一定很好
理解其架构体系了,搞不清楚类动态装载机制和反射机制以及动态代理等等。
       程序员分两种:一种是天才式的人物,不用学习就能在设计和实现上做的完美无缺; 另一种就是
智力平常的普通人,是需要通过读书学习、项目经验、同事朋友间交流沟通来提高技术的。我自己是
后一种人,所以不断的学习C++/java方面的东西,和其它同事沟通。你是那一种人呢?难道你是天才,
是天才请告诉我,我向你请教以便快速提高。
posted on 2008-01-26 18:50 梁-兄 阅读(2602) 评论(12)  编辑 收藏 引用 所属分类: C/C++

Feedback

# re: 面向对象设计中的继承、组合、聚合 2008-01-27 15:42 罗宾李
这个应该可以通过策略模式解决啊。设计上的失误是难免的,你们公司为什么当时做的时候没有review呢?  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-01-27 18:07 cpper
理解万岁
老员工也有年轻的时候 也有激情四射的年代
当结婚生子 年老智衰 上有老下有下的时候,年轻的一代又没有压力,可以拼命加班替代自己的时候,自己的资本只能是自己是公司的元老,熟悉业务,对公司忠诚。
理解他们吧
或许有一天你我也会这样 当然但愿自己到了那个时候已经脱离了编码 不需要面对年轻一代的拿着代码指责  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-01-28 09:56 凤凰竹
实际项目开发过程中,最终的设计往往都是妥协的产物,追求技术上的完美往往是不现实的,比如这个文章的例子,很多的未来需求是可以预见的,但在实现上,究竟做到什么程度,往往要认真把握,这当中就是一个“度”的的问题。

文中对未来的这个需求,没能在最初的设计里面避免感到不解,大可不必,这个需求,也许仅仅是当初所预见的无数未来可能的需求之一而已

作为程序员,从开始的学习,到逐步追求完美,到追求合适的度,都是理念的变化,很多时候,跟对技术的精通程度是无关的  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-01-30 10:51 小四
晕,楼上的不看贴也能回帖,还回了这么一大坨。世界上几乎所有曲曲弯弯的河流,从源头到入海口之间,实际长度与直线距离之比,基本接近于圆周率。爱因斯坦说这是有序与紊乱相争的结果。 梁兄是有序的,老员工是紊乱的,大家都是合理的。  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-01-30 11:25 perlman
中国人说别人的时候往往振振有词。

“c++之父的《c++程序设计语言》、著名的《C++ primer》、经典的《Effective C++》和姊妹
篇《More Effective C++》、四巨头《设计模式》等等关于设计和编程的经典著作。”

看的出来楼主目前的兴趣也只是基于语言级,这些书都是大学刚刚毕业1~2年的新手的重点学习内容,如果还作为“经验”而津津乐道的话,也只是泛泛之辈而已。有时间多看看boost库、ace等重量级作品,哪一天自己的水平能达到改写这些库的程度,也就真正地成熟了。
  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-02-01 13:03 汪江涛
上次发的评论看来有人有意见,删了,我只是想说博主其实是自认为天才的,确要说自己是普通人努力的结果,(如果我说C++之父是天才不知道有没有人有意见?或者我应该说他是很勤奋的白痴合大家的胃口?),所以我犯了个错误,在一个错误的场合谈论了意识形态问题,后果很严重!
博主的文章内容还是很有借鉴性的,写的很好,对此我仅一点意见,“依然写着带类的C程序”没什么问题,面向对象语言和面向对象设计并不等同,当然是紧密相关的,所以“带类的C程序”或许并不是灾难的根本。
还有泛型也算不是什么设计吧?我只能理解它的语言功能的作用,不知道设计上怎么使用“泛型”概念?哪个有实例探讨一下?不胜感激  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-02-01 20:44 罗宾李
搞了半天还在讨论语言、库、模式,不过如此嘛,我不知道博主你研究了ACE等等后,有没有做过什么项目?项目中发现了这些库的优点和缺点了嘛?就算熟得不行了,也就是熟悉罢了,没什么稀奇的吧。不知道博主现在让你写一个快速排序用到的partition函数是否能写出来呢?或者是最普通的Dijkstra是不是都能说清楚呢?  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-03-13 10:24 raof01
面向对象就是要把系统中的真实/虚拟实体抽象成对象并安排其静态/动态结构以及互相之间的沟通/协调。这是属于上一层的东西,一般来说,如果你不具备8~10年的持续OO开发和学习,根本就做不了上层的架构——毕竟天才是少数。而且据我所知,世界上真正一流的软件架构师设计师非常少,大部分架构师、设计师都比较平庸。而无论平庸或是优秀,都是建立在良好的基础之上。举个足球的例子,中国球员小时候就天天联系各种各样的技战术,所以中国年青人在各种国际赛事捷报频频,大了却不过尔尔。
无论你在学习什么,好的基础都很重要。ge health care一位印度籍manager,曾经做过12年的技术工作,基础非常扎实,给我的感触非常深。
看大家讨论里,有些话题转到了类似于“你研究过(看过)XXX吗?用过它吗?”我想,这种问题有点~~弱。因为每个人都有自己的知识面,不可能完全与其他人吻合,你懂得别人未必懂,应该杜绝这样的问题。我参加过不少世界知名的软件公司的笔试,考题基本以基础为主,advanced题有那么几道,平均比重不超过10%
搂主的“在校大学生应该怎样学习”写的很好,不过我觉得不光对于大学生适用,对于任何人都适用。我知道很多人,连C/C++的指针和虚拟都没搞明白就开始天天设计这个流程那个系统。
中国软件与国外软件的差距体现之一就是:在国外公司里,没有坚实的基础,8~10年经验,你就不可能涉及更高层次的工作。而国内的公司,往往有3~4年经验的员工就是顶梁柱了。
当一个程序员连void (*func(int, void (*f)(int)))();都看不懂得时候,你是不能指望他去看懂一些更高级的东西,更别指望能做出好的设计。
  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-05-05 12:51 Touchsoft
同意!

我们的项目没有进行过任何设计!就只管写,我负责做界面,下面设计的3D模块,一个基类能做全部的事情,我曾提议过,头儿根本就不采纳我的意见,他会把你的想法限制在他的思维内。设计的类就是C的函数+数据,没了,也就写几个虚数,那就叫面向对象,我提出的使用的设计模式也没被采用,结果现在一扩展,真受不了。正是因为他们是:老员工,对业务十分熟悉,掌握着公司的业务和技术秘密, 不管设计的如何垃圾,他们总能把功能实现出来,头儿喜欢告诉我们,他在软硬件里有7年经验,我实在不敢恭维。  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-08-08 11:04 雪刀浪子
软件就是在不断失败中前进的,任何事物都不是一踌而就,不然,还要程序员做什么?!
感觉楼主有事后诸葛亮之嫌  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-08-24 12:23 jelver
总体来说,说得还不错  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-11-03 12:41 祥子_随波逐流
刚毕业一年多,很弱,受教了!  回复  更多评论
  



标题  
姓名  
主页
验证码 *
内容(提交失败后,可以通过“恢复上次提交”恢复刚刚提交的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
[使用Ctrl+Enter键可以直接提交]
.NET频道  博客园社区  闪存
网站导航: