常见的编程范式

编程范式也就是编程风格或者说是编程方式,常见的有面向过程、面向对象和事件驱动。

  1. 面向过程:这是原始的传统编程方式,即按步就班得执行程序,非常直观。而且无论怎么编程,局部总是需要过程化得去一步一步处理命令。
  2. 面向对象:这应该是现在用得最多的编程方式,什么都讲面向对象。它的关键是定义对象来做职责划分,使程序中的对象非常接近现实的对象。
  3. 事件驱动:这原本是用于用户界面,以随时响应用户的操作。在Node.js中,它被作为主要的编程方式。

上面几种方式都出自于程序设计的术语,下面试着用吃饭做例子来理解这些编程范式。

编程范式拟人化

1. 面向过程

我们去美食城,先每个摊位去看一下,想吃什么,问问老板多少钱。

决定要吃什么后,跑去收钱的地方,根据刚才问到的价格,给钱,然后拿到票据。

拿着票再跑到摊位上,把票给老板,然后在旁边等着他做好,拿着食物去找座位。

结果座位满了,跑到一个看上去快吃完的人那里,又在旁边等他。

他吃完走了,桌子都没收,你只好把他的东西收拾一下放到旁边。

终于坐下来吃了。

吃好走人。

你吃个饭什么都要搞,当然是很烦,好处是你具体情况都知道。

这里没有突出面向过程的封装,因为这也不是它的特性,但实际上还是有封装的,比如老板怎么抄菜你不用知道,你只要告诉他抄什么就好。

另外,与面向对象相比,面向过程是以抄菜这个动作为单位,面向对象是以老板这个人为单位,老板会抄菜是他的本事。

2. 面向对象

美食城吃个饭真叫烦,这次去肯德基。

进去找柜台服务员,说要吃一个汉堡和一杯可乐。

付完钱后就等着,服务员去找做汉堡的人,等拿到汉堡,再去找倒可乐的人,等可乐倒好也拿到。就把汉堡和可乐一起给你。

你拿着汉堡和可乐,去找位置,结果又满了,你又在一个快吃完的人旁边等着,等他吃完走掉,桌子又没收,你叫服务员,说这里收拾一下。

你在旁边等服务员收拾好,坐下来吃。

吃好走人。

这里就省力多了,你要吃什么,告诉柜台就好,桌子要收拾,告诉服务员就好。

面向对象的设计中,定义边界非常重要,每一个对象应该职责尽可能单一,职责越单一,互相之间的耦合程度必然越松散,后面的的工作可以变得更简单。

你如果叫收银员还要做汉堡,倒可乐,那自然是可以,但是对收银员来说,他不仅与客户、收银机打交道,也要与汉堡机、可乐机打交道,对老板来说,面试、培训、绩效考评的难度也都增加了。

但是,预防过度设计的意识同样重要,设计所关注的无非是工作背后的工作,追求的无非是最高性价比。就这家肯德基门店,拖地的和擦桌子的,也不是一定要分2个工种。

3. 事件驱动

到处都要等,这次搞高端餐馆。

先打电话给高端餐馆,问有位置没?高端餐馆说没有,问你几位,要吃什么。

你说一位,然后点了龙虾和鲍鱼,留了手机号,等他通知你去吃饭。

高端餐馆的高端接线员接到你的订单,去通知大堂经理说,有位高端人士要龙虾和鲍鱼,大堂经理表示明白,接线员就去接别人的电话去了。

大堂经理去跟厨房说,做龙虾和鲍鱼,做好通知我,厨房表示明白。

大堂经理再去跟服务员说,有1人座位时通知我,服务员表示明白。

服务员看到有人吃好走了,他去收拾好,就通知大堂经理说,有位置了。

厨房做完龙虾和鲍鱼,也去通知大堂经理说,菜做好了。

大堂经理看到都完成了,就去跟高端接线员说,都准备好了,叫高端人士来吃吧。

高端接线员用刚才高端人士留的电话,通知高端人士过来吃饭。

高端人士进来,吃饭,走人。

事件驱动真是完美处理,又轻松又不用等,效率那确实高,各种排队都没有。

但事件驱动会需要额外的步骤来处理一些状况:

比如在肯德基,如果不是事件驱动的方式,那收银员走开了,我知道他去处理我的食物,他没回来就是没处理好,不可能在处理别人的东西,而且我也一直等着,一有状况就可以告诉我。这个过程容易控制,因为对我或收银员来说,同时只做一件事,开始了就一定要结束。如果汉堡没了,做汉堡的可以马上告诉收银员,收银员可以马上告诉我,中间不需要额外的过程。如果是高端餐馆,我打完电话,就干别的事去了,如果高端餐馆后面没有再打电话来,我都不知道我是不是订过。当然可以记在脑子里或写在记事本上,每过10分钟看一下哪些事没响应,再做进一步处理。这不是不能做,但相比较我就等在那,处理起来要困难得多。

上面的状况在做架构时,其实完全可以处理掉,并不会成为负担。但为什么面向事件依然没有那么被推崇?主要因为事件驱动将一个业务分割到不同的地方通过事件来驱动,流程上不直观、难理解。大部分时候,从重要性来说,功能的正确性总是最重要的,而不易理解的流程实现大大增加了出错的概率和维护的成本。