梁 兄

QQ: 160216918 QQ群: 26678700

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  56 Posts :: 5 Stories :: 383 Comments :: 0 Trackbacks
         在c++和java世界里,面向对象设计是老话题,基本上看过一两本书,做过一点开发的人,
你问他关于面向对象设计中的继承、组合、聚合,他肯定能回答出来,也会写基类、派生类、
java中的接口等等.
        但实际情况是不是这样呢?在真实的系统开发中,他们设计出来的类层次,真的理解透了
面向对象设计吗,特别是继承、组合、聚合之间的区别吗?前段时间分析了下以前老员工写的
一个模块,这些老员工可是每月8000~9000元的基本工资,年底奖金都是几万,在广州一般国内
企业算很高了,道理上说这些高级c++程序言不论是编码水平还是设计水平,应该是很合格了吧,
应该把类设计的很好,有可扩展性和维护性。实际上呢,让人大跌眼睛,看来实际项目系统中
的设计没那么简单。
        为什么看书时很多人都很明白,一到实际开发就乱套了。你看看书上的例子,每次不是拿
图形来举例,就是拿动物来举例。比如用动物来说明继承关系:
                  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 梁-兄 阅读(1850) 评论(16)  编辑 收藏 引用 所属分类: C/C++

Feedback

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

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

# re: 面向对象设计中的继承、组合、聚合 2008-01-27 20:47 梁-兄
我在这里不可能把很多同事的实际情况写出来,我们是基于模块管理的,一般情况是别人的模块,其他人是不去管理的,除非想多学东西。所以前面人一般不会去review他写的代码。 但我们之间也有接口,忙的时候是配合开工的,为了能全面了解公司系统,我这个人却喜欢阅读公司所有代码,就发现很多问题。当然我这个人也喜欢去看linux内核原代码,glibc代码,可能是很多人无法做的到,也没兴趣的事。
还有就是我自己工作8年,就算在这个公司也是老员工了,工资和他们相差无几。我们基本上从来不会加班,所以我有大量时间去学习; 但很多同事要么热中炒股,要么喜欢玩,基本上是不会象我这样去学习,公司可能就两三个人喜欢学习了。
我也30过了,也结婚等等,也随时一有机会就走向技术管理,所以我感觉我这一类型的开发经验丰富的老员工,应该积极提高设计水平,不然机会来了,却由于自己知识面窄,根本无法做高级架构师、技术经理、技术总监。
当然百分之八九十的技术人员一旦稳定下来,就是在公司慢慢混,一个部门领导的职位毕竟只有一两个,而大部分人也不适合转行,过了35岁,肯定日子越来越不好过。  回复  更多评论
  

# re: 面向对象设计中的继承、组合、聚合 2008-01-27 20:59 梁-兄
还有,我这个人可是一到下班时间,就关机走人回家吃饭,从来不喜欢加班。我认为加班是没什么效果的,人的体力有限,8小时中能集中5小时就不错了。
设计水平应该是随着开发时间越长而越高,不应该搞了五六年还象个刚毕业的,跟结婚生子等一点关系都没有,反而是结婚生子让男人成熟,在设计思考上更深思熟虑.  回复  更多评论
  

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

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

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

# re: 面向对象设计中的继承、组合、聚合 2008-01-28 10:13 梁-兄
这位老兄说得不错, 对这个"度"的阐述很好, 看来实战经验很丰富了.
这篇文章是这么写, 而现实情况我其实并没有要求他在当时想到这个扩展性, 而是这次准备新接一个省移动平台, 我想借机重构成可扩展的架构, 而且是最小改动了, 但他还是不理解\不接受, 十分冷漠地对待, 还想让这一块更乱, 所以我才写了这篇文章抒发心中郁闷.  回复  更多评论
  

# 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-01-30 12:45 梁-兄
仁兄说的对, 我说别人的时候往往振振有词, 自己确实是泛泛之辈而已. c++的库是最难写的, 就是c和java来写一个库, 也不是我这样的人能写出的, 确实不能到达这个境界.
不过我要强调一点, 我提到的书一个是大家公认的, 另外一个就是这些书不是你1~2年就能理解的比较深刻的, 这是很多人忽视了, 要理解得比较深刻,是需要理论与经验结合的.
还有,我因为工作需要, 分析过openH232, ace, apache server, gsoap等开源项目, 自己也分析glibc/linux kernel2.6, 我不敢说能理解得怎么深刻, 但是并不是那种不务实的人, 还是认真得去做了.
我对boost库不感兴趣, 我只学习STL, 标准是最重要的, 除非boost完全引入标准库. ace也其实是中间件, 致命的弱点就是为了跨平台要别人学习它的字符串类开始, 这又是一个MFC, 所以我学习过后, 感觉架构的思想还可以借鉴, 采用它就不必.
所以, 评论与批评是必要的. 好消息就是我的整改方案终于让部门接受, 大家积极起来, 同事还提出引入mfc的RTTI机制以达到动态性. 我是一个坚持的人, 不停说服别人的人, 并不是只说不做.
欢迎大家发表评论, 哈哈   回复  更多评论
  

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

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

# re: 面向对象设计中的继承、组合、聚合 2008-02-02 10:06 梁-兄
欢迎大家积极讨论, 其实我们从发言中可以看出一个人现阶段对技术的关注点.
我研究ACE其实当时是想用它达到跨平台, 后来还买了马达维翻译的<<C++网络编程>>上下两本书, 这也是公司分配的技术调研任务, 当然要你分析出优点和缺点,不然部门人怎么知道决定用不用, 技术调研都是需要调研人分析之后做一个PPT, 给部门所有人进行讲解的, 然后大家根据公司实际项目和技术情况, 决定是否使用. 我不知道其它公司是不是这么做的.
我对算法确实没有研究, 感觉开发游戏的朋友对这个很讲究. 我们平时开发基本上用到的算法,都是可以找到现成的, 不需要自己重新发明轮子,最多根据实际情况修改下, 比如hash算法, 红黑树, 二分查找等等.
对于算法, 就象曾经某个记者问爱因斯坦某个公式怎么写, 爱因斯坦回答就是去查大英百科字典. 对于现在软件开发, 不仅仅是数据结构+算法的模式了, 我们应该关注架构设计, 特别是根据你公司产品和实际项目来决定架构设计, 以达到随着业务变化而需要的很好架构扩展性.   回复  更多评论
  

# 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
总体来说,说得还不错  回复  更多评论
  


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