锁定老帖子 主题:朴实的C++设计
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-11-04
不过有一点是肯定的,C++包含范围太多了。太强大是不是也显得很弱小?
|
|
返回顶楼 | |
发表时间:2010-11-05
piao_bo_yi 写道 jimmy_c 写道 好了。这个例子的讨论到此为止。
还是那个“不装蛋原则”。C++的模板技术,从实践上来说还是很失败的。推出十几年,除了STL和经常用于补裤裆的boost,未见什么GP技术设计的经典之作。我想在这方面想继续尝试的新朋友们可以止步了。至于什么“改变C++设计风格”的炎炎之言,还是少说为好吧! 我推测模板技术应该有很多经典之作,看书中也说STL只是模板技术的一盘小菜了。我只用过BGL库,CGAL中和BGL的结合层,如果没有模板,是搞不定的。 PS;BGL和CGAL是几何算法库。BGL可对任何类型,任何精度要求,任何坐标系的自定义类型无缝结合,非常酷。 http://geometrylibrary.geodan.nl/index.html 问一下,GP技术是啥意思? GP 多半是 generic programming的缩写 |
|
返回顶楼 | |
发表时间:2010-11-17
最后修改:2010-11-17
Solstice 写道 朴实的C++设计
(这篇文章写于 2008 年底,“去年”指的是 2007 年。) 去年8月入职,培训了4个月,12月进入现在这个部门,到现在工作正好一年了。工作内容是软件开发,具体地说,用C++开发一个网络应用(TCP not Web),这是我们的外汇交易系统的一个部件。这半年来,和一两位同事合作把原有的一个C++程序重写了一遍,并增加了很多新功能,重写后的代码不长,不到15000行,代码质量与性能大大提高。实际上,重写只花了三个月,9月我们交付了第一个版本,实现了原来的主要功能,吞吐量提高4倍。后面这三个月我们在增加新功能,并准备交付第二个版本。这个项目让我对C++的使用有了新的体会,那就是“实用当头,朴实为贵,好用才是王道”。 C++是一门(最)复杂的编程语言,语言虽复杂,不代表一定要用复杂的方式来使用它。对于一个金融交易系统,正确性是首要的,价格/数量/交割日期弄错了就会赔钱。在编写代码时,我们特别注意把代码写得尽量简单直白,让人一看就懂。为了控制代码的复杂度,我们采用了基于对象的风,也就是具体类加全局函数,把C++程序写得如C语言一般清晰,同时使用一些C++特性和库来减少代码。 项目中基本没有用到面向对象,或者说没有用到继承和多态的那种面向对象,不一定非得有基类和派生类的设计才是好设计。引入基类和派生类,或许能带来灵活性,但是代码就不如原来透彻了。在不需要这种灵活性的场合,干嘛要付出这样的代价呢?我宁愿花一天时间把几千行 C 代码弄懂,也不愿在几十个类组成的继承体系里绕来绕去浪费脑力。定义并使用清晰一致的接口很重要,但“接口”不一定非得是抽象基类,一个类的成员函数就是它的接口。如果看头文件就能明白这个类在干什么、该怎么用固然很好,如果不明白,打开实现文件,东西都在那儿摆着呢,一望而知。没必要非得用个抽象的接口类把使用者和实现隔开,再把实现隐藏起来,这除了让查找并理解代码变麻烦之外没有任何好处。一个进程内部的解耦意义不大,相反,函数调用是最直接有效的通信方式。或许采用接口类/实现类的一个可能的好处是依赖注入,便于单元测试。经过权衡比较,我们发现针对各个类写测试的意义不大。另外,如果用白盒测试,那么功能代码和测试代码就得同步更新,会增加不少工作量,碍手碍脚。 程序里边有一处用到了继承,因为它能简化设计。这是一个strategy,涉及一个基类和3、4个派生类,所有的类都没有数据成员,只有虚函数。这几个类的代码加起来不到200行。这个设计不是一开始就有的,而是在项目进行了一大半的时候,我们发现代码里有若干处针对请求类型的switch/case,于是我们提炼出了一个strategy,把好几处switch/case替换为了strategy对象的虚函数调用,从而简化了代码。这里我们纯粹把OO当做函数指针表来用的。 程序里还有几处用了模板,甚至是type traits,这都是为了简化代码,少敲键盘。这些代码都藏在一个角落里,对外只暴露出一个全局函数的接口,使用者不会被其困扰。 项目里,我们惟一仰赖的C++特性是确定性析构,即一个对象在离开其作用域之后会保证调用析构函数。我们利用这点大大简化了代码,并确保资源和内存的回收。在我看来,确定性析构是C++区别其他主流开发语言(Java/C#/C/动态脚本语言)的最主要特性。 为了确保正确性,我们另外用Java写了一个测试夹具(test harness)来测试我们这个C++程序。这个测试夹具模拟了所有与我们这个C++程序打交道的其他程序,能够测试各种正常或异常的情况。基本上任何代码改动和bug修复都在这个夹具中有体现。如果要新加一个功能,会有对应的测试用例来验证其行为。如果发现了一个bug,先往夹具里加一个或几个能复现bug的测试用例,然后修复代码,让测试通过。我们积累了几百个测试用例,这些用例表示了我们对程序行为的预期,是一份可以运行的文档。每次代码改动提交之前,我们都会执行一遍测试,以防低级错误发生。 我们让每个类有明确的职责范围,一个类代表一个概念,不能像个杂货铺一样什么都装。在增加或修改功能的时候,仔细考虑在哪儿下手才最合理。必要时可以动大手脚,而不是每次都选择最简单的修补方式,那样只会使代码越来越臭,积重难返,重蹈上一个版本的覆辙。有时我们会提炼出一个新的类,把原来分散在多个类里的代码集中到一起,从而优化结构。我们有测试夹具保障,并不担心修改会破坏什么。 设计不是一开始就形成的,而是随着项目进展逐步演化出来。我们的设计是基于类的,而不是基于类的继承体系。我们是在写应用,不是在写框架,在C++里用那么多继承对我们没好处。一开始我们只有三四个类,实现了基本的报价功能,然后增加了一个类,实现了下单功能。这时我们把报价和下单的共同数据结构提炼成一个新的类,作为原来两个类的成员(而不是基类!),并把解析客户输入的代码移到这个类里。我们的原则是,可以有特别简单的类,但不宜有特别复杂的类,更不能有大怪兽。一个类太大,我们就看看能不能把它拆成两个,把责任分开。两个类有共同的代码逻辑,我们会考虑提炼出一个工具类来用,输入数据的验证就是这么提炼出来的一个类。勿以善小而不为,所以始终能让代码保持清晰易懂。 让代码保持清晰,给我们带来了显而易见的好处。错误更容易暴露,在发布前每多修复一个错误,发布后就少一次半夜被从被窝里叫醒查错的机会:) 不要因为某个技术流行而去用它,除非它确实能降低程序的复杂性。毕竟,软件开发的首要技术使命是控制复杂度,防止脑袋爆掉。对于继承要特别小心,这条贼船上去就下不来,除非你是继承boost::noncopyable 讲解面向对象的书里,总会举一些用继承的精巧的例子,比如矩形、正方形、圆形继承自形状,飞机和麻雀继承自“能飞的”,这不意味着继承处处适用。我认为在C++这样需要自己管理内存和对象生命期的语言里,大规模使用面向对象、继承、多态多是自讨苦吃。还不如用C语言的思路来设计,在局部用一用继承来代替函数指针表。而GoF的《设计模式》与其说是常见问题的解决方案,不如说是绕过(work around)C++语言限制的技巧。当然,也是一些人挂在嘴边用来忽悠别人或麻痹自己的灵丹妙药。 真知灼见啊! 我上一次正经用甚至玩C++都是八年前的事了. 现在一直在用Java. 不过不管是基于我过时的C++经验, 还是现在用Java的感觉, 我的观点都和你是惊人的相似. 我搞C/C++的时候也用宏和模板搞些奇技淫巧, 因为有些特殊时候还就是这些毒草能简化代码. 不过总体设计上说, 真还就最好是基本的类+尽量少的间接层(包括继承, 多态, 甚至模板多态). 不过stl还是要用. 感觉这些原则在java里也一样适用. 是的, 我们避免不了要用些反射啦, aop啦之类的魔法, 但是这些不应该是设计的主体. 很多人上来就先来个interface, 让你觉得好像多灵活似地, 但其实接下来不过就是一个FooImpl. 最后一些不需要的灵活性, 脱裤子放屁般的伪封装到处都是, 除了让程序不容易理解, 没起什么正面作用. 动不动就"松耦合". 问题"耦合"不是越松越好. "松耦合"让单独的小模块更独立, 相对更容易单元测试, 但是过度"松"就会造成程序的关联更加隐蔽晦涩. 很多程序模块之间是有关联甚至因果关系的. 强行割裂了来看可能更费解. 而"紧耦合"的好处是理解两个相关模块之间的联系更容易. 黑盒白盒也相对同意. 不过还是不能走极端吧. 如果完全黑盒的话, 测试代码会比较稳定, 改动相对容易. 但是缺点是一些复杂的逻辑和边界条件不容易测试, 而且测试一旦报错, 查错也相对比较难. |
|
返回顶楼 | |
发表时间:2010-11-17
没想到楼上的潜水牛还会冒泡
|
|
返回顶楼 | |
发表时间:2011-01-28
我觉得还是适用为先,空谈误人!!呵呵
|
|
返回顶楼 | |
发表时间:2011-03-16
面向流程的业务的确不太需要oo,因为不存在过多继承的模型
电信的数据接口标准也是典型的裸结构,以manager作为结构和机构的关系链接 |
|
返回顶楼 | |
发表时间:2011-06-23
朴实而不简单,好!
|
|
返回顶楼 | |
发表时间:2011-07-11
一晃三年过去了.不知道lz现在怎么想的
|
|
返回顶楼 | |
发表时间:2011-07-15
lanyan 写道 一晃三年过去了.不知道lz现在怎么想的
http://blog.csdn.net/Solstice/article/category/793463 |
|
返回顶楼 | |
发表时间:2011-07-15
Solstice 写道 lanyan 写道 一晃三年过去了.不知道lz现在怎么想的
http://blog.csdn.net/Solstice/article/category/793463 你偶尔也会冒个泡在这里... |
|
返回顶楼 | |