编程范式白话说
常见的编程范式
编程范式也就是编程风格或者说是编程方式,常见的有面向过程、面向对象和事件驱动。
- 面向过程:这是原始的传统编程方式,即按步就班得执行程序,非常直观。而且无论怎么编程,局部总是需要过程化得去一步一步处理命令。
- 面向对象:这应该是现在用得最多的编程方式,什么都讲面向对象。它的关键是定义对象来做职责划分,使程序中的对象非常接近现实的对象。
- 事件驱动:这原本是用于用户界面,以随时响应用户的操作。在Node.js中,它被作为主要的编程方式。
上面几种方式都出自于程序设计的术语,下面试着用吃饭做例子来理解这些编程范式。
编程范式拟人化
1. 面向过程
我们去美食城,先每个摊位去看一下,想吃什么,问问老板多少钱。
决定要吃什么后,跑去收钱的地方,根据刚才问到的价格,给钱,然后拿到票据。
拿着票再跑到摊位上,把票给老板,然后在旁边等着他做好,拿着食物去找座位。
结果座位满了,跑到一个看上去快吃完的人那里,又在旁边等他。
他吃完走了,桌子都没收,你只好把他的东西收拾一下放到旁边。
终于坐下来吃了。
吃好走人。
你吃个饭什么都要搞,当然是很烦,好处是你具体情况都知道。
这里没有突出面向过程的封装,因为这也不是它的特性,但实际上还是有封装的,比如老板怎么抄菜你不用知道,你只要告诉他抄什么就好。
另外,与面向对象相比,面向过程是以抄菜这个动作为单位,面向对象是以老板这个人为单位,老板会抄菜是他的本事。
2. 面向对象
美食城吃个饭真叫烦,这次去肯德基。
进去找柜台服务员,说要吃一个汉堡和一杯可乐。
付完钱后就等着,服务员去找做汉堡的人,等拿到汉堡,再去找倒可乐的人,等可乐倒好也拿到。就把汉堡和可乐一起给你。
你拿着汉堡和可乐,去找位置,结果又满了,你又在一个快吃完的人旁边等着,等他吃完走掉,桌子又没收,你叫服务员,说这里收拾一下。
你在旁边等服务员收拾好,坐下来吃。
吃好走人。
这里就省力多了,你要吃什么,告诉柜台就好,桌子要收拾,告诉服务员就好。
面向对象的设计中,定义边界非常重要,每一个对象应该职责尽可能单一,职责越单一,互相之间的耦合程度必然越松散,后面的的工作可以变得更简单。
你如果叫收银员还要做汉堡,倒可乐,那自然是可以,但是对收银员来说,他不仅与客户、收银机打交道,也要与汉堡机、可乐机打交道,对老板来说,面试、培训、绩效考评的难度也都增加了。
但是,预防过度设计的意识同样重要,设计所关注的无非是工作背后的工作,追求的无非是最高性价比。就这家肯德基门店,拖地的和擦桌子的,也不是一定要分2个工种。
3. 事件驱动
到处都要等,这次搞高端餐馆。
先打电话给高端餐馆,问有位置没?高端餐馆说没有,问你几位,要吃什么。
你说一位,然后点了龙虾和鲍鱼,留了手机号,等他通知你去吃饭。
高端餐馆的高端接线员接到你的订单,去通知大堂经理说,有位高端人士要龙虾和鲍鱼,大堂经理表示明白,接线员就去接别人的电话去了。
大堂经理去跟厨房说,做龙虾和鲍鱼,做好通知我,厨房表示明白。
大堂经理再去跟服务员说,有1人座位时通知我,服务员表示明白。
服务员看到有人吃好走了,他去收拾好,就通知大堂经理说,有位置了。
厨房做完龙虾和鲍鱼,也去通知大堂经理说,菜做好了。
大堂经理看到都完成了,就去跟高端接线员说,都准备好了,叫高端人士来吃吧。
高端接线员用刚才高端人士留的电话,通知高端人士过来吃饭。
高端人士进来,吃饭,走人。
事件驱动真是完美处理,又轻松又不用等,效率那确实高,各种排队都没有。
但事件驱动会需要额外的步骤来处理一些状况:
比如在肯德基,如果不是事件驱动的方式,那收银员走开了,我知道他去处理我的食物,他没回来就是没处理好,不可能在处理别人的东西,而且我也一直等着,一有状况就可以告诉我。这个过程容易控制,因为对我或收银员来说,同时只做一件事,开始了就一定要结束。如果汉堡没了,做汉堡的可以马上告诉收银员,收银员可以马上告诉我,中间不需要额外的过程。如果是高端餐馆,我打完电话,就干别的事去了,如果高端餐馆后面没有再打电话来,我都不知道我是不是订过。当然可以记在脑子里或写在记事本上,每过10分钟看一下哪些事没响应,再做进一步处理。这不是不能做,但相比较我就等在那,处理起来要困难得多。
上面的状况在做架构时,其实完全可以处理掉,并不会成为负担。但为什么面向事件依然没有那么被推崇?主要因为事件驱动将一个业务分割到不同的地方通过事件来驱动,流程上不直观、难理解。大部分时候,从重要性来说,功能的正确性总是最重要的,而不易理解的流程实现大大增加了出错的概率和维护的成本。