OpenClose原则
前一阵看到陈天老师的一篇文章,标题是谈谈我对工程和管理的看法.这是一篇含金量异常高的文章,强烈建议仔细阅读.这篇文章还使我开始尝试学习Clojure,因为Rich Hickey那篇Simple Made Easy实在是太诱人了…
从这篇文章里,我知道了写代码的一个原则: Open to extension, Close to modification
. 即代码写完以后,保持扩展能力,但不需要再改动代码.
我目前的理解就是:把条件检测
和执行的任务
组织成一系列的成对数据,有新的情况要处理时候,只要增加相应的数据就行了(Open to extension),而选择并执行任务的代码用一个遍历函数完成,不再需要修改(Close to modification).另一种理解角度就是任务分解,把包含多个逻辑,将来有可能增加逻辑的任务分解成单逻辑独立任务.
最小的使用场景,执行任务是一个表达式
一个常见的场景,根据编码返回对应文字,type为客户端请求参数数字,现在要取得对应的文字.直接的写法就是if加修改返回结果.
1 | function getTypeName(type) { |
这是工作中的一个例子,其实以前确实只有3种,现在变成了4种,没准以后还会增加,PM的idea,你懂的.下面是采用OpenClose原则的写法:
1 | function getTypeName(type) { |
虽然在这个例子看不出明显优势,但选择逻辑有时候会很多,执行逻辑有时候会很长,很乱,这时候使用这个原则的好处就会更明显.
大一点的使用场景,执行任务是一个函数
这次需要格式化从DB取回的数据,正好还是上面例子的路由里出现的,由于客户端请求了不同类型的数据,所以要根据对应的类型对返回数据进行相应的格式化.这次直接看采用这个原则的写法.
1 | function formatActWithDetail(act, matched) { |
可以看到,返回数据有相似,也有差异,有的还有自己单独的逻辑如果写在一起,即难看,又痛苦,又不好扩展,因为扩展时候又是一次即难看又痛苦的经历.这时候OpenClose写法的好处已经比上个例子明显了很多.
更大的使用场景,执行任务是一个业务逻辑
有时候一个api实际上包含好几种不同的业务逻辑,但由于某些原因(可能是客户端用一个api更合适),这个api并没有在客户端拆分成多个api,而是带着多个逻辑的所有参数用一个api请求服务端,这时候如果写在一起,直接用if语句判断参数并执行对应的业务逻辑,开发过程就开始忍无可忍了,因为太多的东西需要同时考虑.这时候OpenClose原则可以很好的发挥威力.即直接把这个api根据请求参数,拆分成多个内部业务逻辑.既降低了开发痛苦度,也保持了扩展性.
看一个上述描述的具体例子,多种分享用一个接口,各个分享的相似和差异有大有小,开发过程中分享类型从3种增加到了5种,直接看OpenClose的写法吧.
1 | module.exports = function(req, res) { |
可以看到,5种分享内容,每种又有很多种分享渠道,其中有的渠道需要返回附加的数据.我把所有可能的参数拼成一个args
对象.然后直接通过type
参数,把这个api拆分成5个业务逻辑单一的内部处理模块,每个模块放在单独的文件里,把所有需要的数据全部传过去,这层api就不再干其他事情了.
看一下其中的一个处理模块action-active.js
:
1 | module.exports = (args, res, req) => { |
可以看到,这是一段单一业务逻辑处理的代码,不需要在编码的同是考虑不同的业务逻辑.只需要处理这个业务逻辑,并返回数据.可以想象一下把所有5种混在一起,而且将来没准会增加分享类型的情况下,代码里会到处充满了if,而OpenClose一旦搭好,每个业务逻辑的开发过程就都享受到单一业务逻辑带来的清晰明了,同时现存业务逻辑的修改,新增新的业务逻辑,都不会影响其他业务逻辑.
欢迎交流指正
水平有限,如果您发现了其他好的使用场景,或者我理解的不正确,不全面的地方,请务必告诉我,非常感谢!