从具体的语言和实现中抽离出来,面向对象思想究竟是什么?

灵魂拷问

面向对象的思维方式

面向对象与面向过程

先看这样一个例子:如果有同事问你怎么办理离职手续,你会怎么对他说呢?

也许你会这样说:

  • 首先,提离职申请,和同事做交接,该push的代码都push上去、该留的文档都留下来;
  • 交接完毕后,告诉你的领导你要哪天走,让他批一下你的离职流程;
  • 等领导审批通过之后,把电脑、显示器、工牌、垃圾桶什么的都得交还行政;
  • 清点没问题了,到last day那天再去找行政,行政会给你开一个证明;
  • 最后拿着这个证明去找财务结算工资,算清楚之后拿着财务给的证明去找人力,人力会给开离职证明。

或者,你会这样说:

  • 首先,提离职申请;
  • 然后依次找工作交接人、领导、行政、财务和人力,跟他们说“我来办离职手续”,按他们的要求走完流程;
  • 最后拿到离职证明,就办完了。

为什么你这么熟练,你到底离职过多少次了!?

两种说法看起来差不多,其实背后的思维方式大不相同。

第一种就是典型的面向过程的思维:做事过程的每个步骤和全部细节都掌握在你自己的手中。因而,你要了解做事的所有步骤,亲力亲为地落实每一个细节。

第二种则是面向对象的思维:步骤和细节被拆分并委托给了各个岗位工作人员;你只需要和他们对接,具体事宜由他们负责。

当然,面向对象最终还是要面向过程。无论我们拆分多细、委托给谁,负责人还是要按一定的步骤来完成自己的工作,你还是要把每个人的工作组织成一个大的过程才能完成整个项目。

可见,面向对象和面向过程的区别并不在于过程的实现细节,而在于如何将过程中的步骤和局部的细节组织为完整业务。

面向对象与管理思想

从“将局部细节组织为完整业务”这个角度来看,与其说面向过程和面向对象是技术思想,我更愿意把它看作一种管理思想,与管理公司的思维方式异曲同工。

当公司规模不大、业务比较简单时,一个人就可以把市场人力财务行政一把抓。这种管理思路,就是面向过程的思想。

面向过程是一种基层办事的思维方式:先整理材料,再写PPT,然后向领导汇报,接着逐级审批,最后开会宣导。从这种思路出发,我们很容易想到先出需求后开发、先定义接口后开发代码、先拼SQL再查库、先写完代码后测试。同为基层码农,大家思维方式很接近,所以都很容易理解面向过程的代码、功能和系统。

当公司做得越来越大、业务越来越复杂时,一个人就很难事无巨细一肩挑了。这时,我们就需要划分职权、拆分部门,只要一件事落到了负责人身上,就认为这件事能够最终落地。

这种管理思维,就是面向对象的思想。相比面向过程,面向对象有点更像高层管理的思维方式,也就是只关心“谁来做”、“做什么”,不关心具体“怎么做”:这个事儿你先找那个部门,再找那个总监签字,最后安排你的人去落实到客户;这个项目由小李负责,小张小王你俩协助下。这与“这个功能需要先调这个接口、再调那个接口”、“这项业务主要放在A系统,B系统和C系统提供基础数据服务”何其相似。

这种思维方式,与开发者们的过程管理的思维方式大不一样。类似的,依据面向对象思想开发的代码也容易让人费解——我的代码就总也逃不出被同事们疯狂吐槽的命运。

大佬你好么

技术层面上看系统和业务的发展,和管理层面上看公司的发展如出一辙。

如果一个系统、一项业务的处理逻辑比较简单——总共就一两张表,三四个if——那就面向过程,按照流程一步步实现了就好。

如果业务逻辑非常复杂,从“一去二三里、烟村四五家“逐渐发展成了“只在此山中,云深不知处”,那就需要认认真真地思考一下顶层设计了。此时,面向对象思想就有了用武之地。

面向对象与模拟现实

从公司管理到小组管理,从项目管理到自我管理,现实世界中,管理无处不在。面向对象思想作为一种“管理思想”,其实它只是在模拟现实世界中的管理方法——甚至可以说,面向对象就是在模拟现实世界。

在现实世界中,我们会把一项职责分配给一个岗位,在面向对象中我们会把一项职责分配给一个类。

在现实世界中,每个岗位上都可以有不同的员工,在面向对象中,每个类都可以有不同的实例。

在现实世界中,每个岗位都有自己的Title和Job Description,在面向对象中,每个类都有自己的抽象和实现。

在现实世界中,大家都希望自己的工作少受别人的影响,在面向对象中,我们希望每个类都做到高内聚、低耦合……

更不用说在学校学的:“鸟”是一个父类,“麻雀”、“喜鹊”是它的子类这样的“仿生学”面向对象了。

还记得这个问题吗:“鸵鸟”应不应该继承“鸟”类?

小时候学写作文时,老师教我们:在生活中多观察、多思考,写作文就会变得很简单。面向对象也是如此:在现实生活中多留心、多思考,面向对象思想也会变得很简单。

面向对象的问题

如果还是觉得面向对象很费解,我想,除了思维方式不同之外,主要有两个原因。

首先,要建立和理解一套合理的“类”本身就很困难,更何况这个“类”的定义还一直在变化。

即便在现实世界中也是如此。

随着人们对天体物理学有了更深入理解,“行星”这个类也有了更准确的定义,冥王星也因此退出了行星的行列,太阳系又回到了八大行星的时代。

随着生物学的不断进步,动植物的分类也在不断地做着调整,原有的门纲目科属种已不足以描述生物分类,人们不得不创建了各种亚门、亚纲、亚目来满足新的需求。

创立、发展了数百上千年的学科尚且如此,何况“新兴”的计算机科学?更何况野蛮生长几个月所产生的计算机系统?

其次,有很多东西我们确实不关注“分类”,而只关注如何使用。

我们吃鳗鱼饭时,会关注里面的鳗鱼到底是脊索动物门圆口纲七鳃鳗目七鳃鳗科七鳃鳗属的七鳃鳗还是脊索动物门硬骨鱼纲鳗鲡目鳗鲡科鳗鲡属的鳗鲡吗?不会,我们只关注它好不好吃。

我们在使用牛顿-莱布尼兹公式时,会关注它到底是牛顿先提出的还是莱布尼兹先提出的吗?不会,我们只关注它能不能解题得分。

我们在使用函数时,会关注它到底属于哪个类的哪个实例吗?不会,我们只关注它能不能实现功能。

但在面向对象中,这些东西都要先分类、然后才能为我所用。为了把这些东西归入合适的分类中,面向对象需要给自己多找很多麻烦,因而也更加难以理解。

最后,面向对象要把完整过程拆分成子流程,并将其委托给不同的对象。这导致每个对象都只掌握一部分过程。想要看到业务全貌,就必须把各个对象手中的“碎片”收集并拼接起来。每一个写过面向对象系统的人应该都能理解个中滋味。

为什么还要使用面向对象

面向对象思想如此费解又麻烦,那我们为什么还要使用它呢?

西医和中医都诞生于人类的蒙昧无知。西医也曾经有过诸如灌肠疗法、放血疗法、甚至“前脑叶白质切除术”这种医疗手段。虽然很多时候这些医疗手段无异于草菅人命,但有时还算有用,还算有一定的疗效。

但是西医没有满足于“有用”,而是更深入的探索了“是什么”和“为什么”。最终,西医建立起了一套现代医学体系,在"有用"这方面,比传统西医高到不知道哪里去了。

曾经,生物学的命名体系非常混乱,各国学者都自说自话地给自己发现和研究的动植物命名。结果,学界出现了大量同物异名、异物同名的现象,学术交流几乎完全陷入鸡同鸭讲的困境之中,学科发展受困于此,几乎止步不前。

林奈老爷子提出了门纲目属种(“科”是后人加上去的)的分类方式和双名法的命名方式,建立了一套完整的、规范的体系。生物学这才走上了正轨,并发展进步到了现在的水平。

当然,林奈老爷子并不姓林,人家大名叫“卡尔·冯·林奈”

面向对象思想也有类似的作用。

面向对象设计不仅能实现业务上“做什么”的需求,还能促进我们去思考业务“是什么”和业务应该“怎么做”,更能鞭策我们逐步完善“是什么”、改进“怎么做”,并最终更快、更好、更新的满足“做什么”。

不仅如此。依据面向对象思想创建起来的业务领域模型,为业务、产品、开发、测试提供了一套完整的、规范的体系,对各方协同、共同促进系统和业务的发展有着不可估量的作用。

因此,在“言必称微服务”、“系统不用Redis,便称英雄也枉然”的今天,我还是决定把自己对面向对象思想的理解细细地梳理一遍,在从“有经验”进步到“有体系”的过程中,也更深入地探寻“是什么”和“怎么做”,以求更快、更好、更新地满足“做什么”。