编程实践:C++风格习题1
前言
近期买了本《C++编程风格》,这本书有些老,1992年,很多理念有些过时,但还是作为休闲读物。 书中的实例打算就作为编程练习,学习C++的面向对象编程思路。
补充
这本书还挺有意思的,已读完,另外也看了诸如《SICP》,《the litte java》等书, 对面向对象,代码组织有了更深刻的理解, 本文是曾经的思考,现在看来都懒得读下去,记录自己的成长,留作纪念。
习题
习题1是练习对于抽象的理解,题目大致是:
确定一台计算机各种配置价格,
由两部分构成:
扩展卡 + 显示器
扩展卡可选enum {光驱, 磁带机, 网络接口}
显示器可选enum {单色, 彩色}
还有就是按照源码,扩展卡中的光驱CDRom有折扣,其他的没有
待改进的源码就不贴了,总之各种price,name函数都可以被抽象提炼,避免重复使得程序复杂。 而且各种switch case明显就是抽象成一个基类嘛。
再看改进代码前,我先整理自己的思路,而且我不局限于书中的case,综合考虑基本需求和需求变化。 只是拿这个例子做练习,貌似书中的思路也很一般。
整理思路
问题分析
设计类之前,先分析一下待改进的源码中有哪些地方值得修改:
- 无论扩展卡还是显示器,还是未来的其他组件,都一定有price, name函数,源码各种switch,所以要设计基类及虚函数
- 假设未来需求有变化,比如多个移动硬盘什么的,所以计算机价格应该是某些组件的accumulate
- 但是组件也有限制条件,假设通常意义来说计算机只可能有1个扩展卡,1个显示器等等。
- 假设有的商品没有rebate,有的有,那么假设未来需求还需要统计有rebate的商品
- 假设user在选择商品时,可以重选,删除,增加。
恩,问题已经被我各种限制条件设计得越来越复杂了
设计基类
我想到两种方式 一种包含private的name和price,构造函数中输入name和price, 用普通的成员函数getName和getPrice。
第二种,name,price的虚函数,这是我浅薄理解的“重接口,轻实现”, 这样处理的优点是: 万一price的计算方法有变化之类可以方便地调整计算方式, 比如,有的price需要考虑rebate,而有的不需要,那么我就在接口层面统一地getPrice,而针对不同子类不同实现。 而如果用普通函数,计算方式就写死了。
然而,对于此问题,我更欣赏第一种方式,因为基类设计成虚方法子类一个个实现很累, 假设为了简化,子类如果再细分成有rebate和没有rebate的呢? 那么假设有变更,一个rebate类如何变成一个非rebate类?问题变得更复杂。
而如果我假设rebate等于一个特殊值,例如0.0表示没有rebate即可(且在构造函数中将rebate默认值设计为0), 这样便可以用forall-if-statement统计哪些有rebate,哪些没有了。 还有, 是否设计一个bool类型的isRebated inline成员函数呢?我觉得,可能会有问题, 因为该句会放在for循环内,
那是否需要isRebated普通成员函数呢?Stroustrup有个观点,类中非必要的成员函数别添加, 我觉得很有道理,似乎没有必要,用处不大。
补充总结
想的太复杂了,没必要,因为不是行为的不同而是数据的不同,简单处理的话,可以用同一个类。 除非遇到复杂的问题时,再应该考虑组织复杂的类层次结构。