C++面向对象之内核、实现、反思与救赎

  说实话这篇博客我酝酿已久,但却迟迟未下笔,主要原因一方面在于觉得自己目前还难以驾驭这样宏大的命题,对我这样一个连入门级菜鸟都算不上的人而言,谈论这种话题难免流于表层,沦为纸上谈兵;另一方面很多东西我虽然若有所思,但还需假以时日,在大量的编码实践中才能锤炼成型.但是我写技术博客主要的目的还是用于记录、分享自己在技术成长道路上的一些思考,哪怕日后回头再看显得幼稚可笑,也无伤大雅,毕竟是成长的历程嘛,所以这里还是决定抛砖引玉.

  其实长久以来,面对编程我心里总是会犯怵,通俗点说叫有点虚,这并不是说我无法用语言实现相应的功能,而是觉得自己在更高的层面上对程序设计缺乏一种思考框架,就仿佛少了根主心骨.今天你让我写个PageRank算法,我能给你撸出来;明天你让我实现三维人体动画,我花点功夫也能整出来.但是一些更基本的问题,却长久的困扰着我,或者说市面上看到的答案并不能很好的说服我,例如:

  到底为什么需要类?书上明明说用类来表示概念才是精华,可你看我什么类也不用不照样把PageRank,Hits算法实现的好好的嘛;

  面向对象又是什么?随手翻开一本教材书上一会说面向对象有三大特征:封装+继承+多态;一会又是说面向对象是对现实世界的模拟,所谓一切都是对象,对象之间通过消息机制来沟通;然后再过几天看了个安卓教学视频,里面的老师讲的又是面向对象的终极意义在于减少重复代码......然后我就各种凌乱了,抓不住灵魂,也无法建立起一个相对清晰的思维框架.

  还有设计模式呢?昨天刚听人说设计模式和重构才是软件开发的倚天屠龙,今天一打开知乎然后发现怎么下面的回答清一色全是在喷设计模式呢?打开四人帮的书一看发现居然有23种模式呢,这对我这种记忆力差的人可谓灾难,难道我应该苦修数载把这23个设计模式都背的滚瓜烂熟、了然于心,然后使用的时候在头脑中遍历一遍看看哪个最适合?

  ......

  诸如此类.

  前面提到一个词,叫思考框架,其实在程序设计的世界中有更为专业的名称,叫做编程范式.我最开始是在《Effective C++》这本书上看到这个词的.所谓编程范式并不神秘,就是在你编程的时候面对具体问题时的抽象方式;而面向对象,则仅仅是编程范式的其中一种,如此而已.都说C++是世上最复杂的语言,原因之一就在于它可以支持多种不同的编程范式:过程式范式(顺序选择循环);抽象数据类型ADT(封装,值语义);基于对象(具体类,封装,对象语义);面向对象(抽象类,封装+继承+多态);泛型编程;模板元编程;函数式编程.就像美国是一个联邦制国家一样,不同的州适用不同的法律,对于C++而言也是一样,在不同的范式下有着截然不同的适用原则.不信你翻开《Effective C++》p105倒数第二段,就知道我所言不虚.

  这里,让我们暂且将目光局限于面向对象的世界.我们到底该去如何把握面向对象呢,它的内核到底是什么?

  最初拯救我于思维的泥潭之中的是知乎上一位前辈invalid's的这个回答.这篇回答我前后看了不下十遍,甚至在纸上写过好几遍,当时真有一种久旱逢甘霖的感觉,因为它实实在在的解答了我心中一些长久以来的困惑.当然现在回过头再看,这个回答是有它自身的局限性的,它所描述的面向对象的内核固然精辟入里,但却仅仅只是面向对象抽象机制的流派之一,而这也正是以C++为代表的,建立在分类的基础上的,以类的设计(而非对象)为中心的面向对象机制的局限所在(僵化的静态类体系设计难以描述与应对动态的现实世界;is-a带来强耦合,"只要就"沦为了"只有才"),我在后面会详细谈到.但无可否认的是,它帮我建立了一个最初的思维模型,从那之后我在心中明确了如下几点:

  面向对象=封装+(继承、多态);面向对象≠封装+继承+多态,继承(接口继承)和多态是一枚硬币的正反面,而不是平等的关系,多态是目的,继承仅是实现多态的手段;

  而面向对象的好处是:(一切不谈好处的编程范式都是耍流氓)

  1.通过封装隐藏内部实现,暴露给用户接口,使得接口和实现分离,用暴露于外部的类接口屏蔽了内部变化(成员变量),并且使得用户能够以安全、规范的方式使用类;

  2.多态归一化.归一化即简化用户的使用.通过提炼出一个公共基类提供接口(可继续细分为:基类提供纯虚函数对应接口继承only,提供impure虚函数对应接口继承及缺省实现继承,提供非虚函数对应接口继承及强制性实现继承);而派生类继承基类并负责实现(override基类虚函数),具体在C++中,是通过将基类的引用或指针指向派生类对象,就能得到使用简洁、统一的接口(主要是基类的虚函数)获取丰富多彩的内在执行逻辑(即任一子类的实现)的好处.

  如果第二点你觉得不够形象,我举个生活中的例子你立马就能明白多态的好处了:例如插电插头,电插头所属的电器种类、数量不计其数,接线板背后的线路更是复杂无比,但是这些都无所谓,对于用户而言,在我想要使用的时候只需要简简单单的将插头对准插孔插进去,一切就OK了.至于格力电风扇和海尔电热水器的内部电路是怎样的我根本不知道也无需关注.试想如若不然,每当我从外面买回来一种新的电器我要对着用户手册学上个十几分钟才能学会插插头,或者需要有专业工作人员来对我进行培训一番,那岂不是要崩溃.什么是归一化的好处,这就是.一言以蔽之,归一化即是为了简化用户的使用逻辑.

  面向对象(以C++的面向对象编程范式为代表的面向对象)的好处就这两点.

  在明确了面向对象的好处之后,我们可能更关心的是下面两个问题:1.面对业务需求时,我们该如何判断何时适用面向对象何时不适用;2.以及在使用面向对象进行设计时,有没有简洁有力的原则供我们把握?

  以上两个问题我认为后者更容易回答一些,重要的话说三遍:

  在使用面向对象抽象机制时,接口兼容才是你该关注的.

  在使用面向对象抽象机制时,接口兼容才是你该关注的.

  在使用面向对象抽象机制时,接口兼容才是你该关注的.

 

  然而,这并非面向对象的全貌.

  未完待续......

posted @ 2015-08-27 18:40  _江湖夜雨十年灯  阅读(313)  评论(1编辑  收藏  举报