首页 > 代码库 > 连载:面向对象葵花宝典:思想、技巧与实践(31) - OCP原则

连载:面向对象葵花宝典:思想、技巧与实践(31) - OCP原则

开闭原则是一个大部分人都知道,但大部分人都不懂的设计原则!惊讶


====================================================================

OCP,Open-Closed Principle,中文翻译为“开闭原则”。

 

当我第一次看到OCP原则时,我的感觉就是这原则也太抽象了吧,什么开,什么闭呢?

 

然后我去寻找更加详细的答案,最经典也是最常见的解释就是维基百科了:

http://en.wikipedia.org/wiki/Open/closed_principle 

"software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification";

翻译一下就是:对扩展开放,对修改封闭

 

虽然这句解释更详细了,但其实还是很难理解,我因此去请教了一个前辈高人,他的回答更加惊世骇俗:不修改代码就可以增加新功能!!

 

当时我听到这句话就震惊了,这是多么神奇的事情啊,不修改代码就能够增加新功能!

但问题是:怎么做到的呢?难道这个原则是有关人工智能,又或者有什么高超的技巧,能够做到不修改代码增加新功能?

 

这么牛逼的原则当然要继续探索了,但怎么也没有找到“不修改代码就可以增加新功能”的独门秘籍!

 

于是对这个原则有了怀疑,经过继续的探索和查看各种资料,才发现原来是各位大师们在解释这个原则的时候隐藏了非常重要的“主语”,而这才是OCP原则的关键!

 

大师们省略的主语一个就是consumer(翻译成使用者、消费者),一个就是provider(翻译成生产者、提供着),例如A类调用了B类的方法,则A就是consumer,B就是provider。

 

完整的OCP原则实际上应该这样表述:open for provider extension,closed for consumer modification,翻译一下就是:对使用者修改关闭,对提供者扩展开放!

 

更通俗的意思就是:提供者增加新的功能,但使用者不需要修改代码

 

虽然到这里我们已经基本上将OCP原则解释清楚了,但实际上细心的朋友还是会发现有问题的:提供者增加新的功能,使用者不修改代码就能用上么?

比如说:你设计一款有关车游戏,需要设计一个“car”的类,这个类原来有“加速”、“刹车”、“转向”三个功能,现在你要加一个新功能“改装”,游戏中其它类例如player,不修改代码就可以用上“改装”这个功能么?

 

很显然这是不可能的,我都新加了一个函数,你都不调用就能用新的功能,这也太邪乎了吧?

 

答案在于所谓的增加新功能,并不是增加一个全新的功能,而是原有的功能有了替代实现,这也是英文的“extension”所隐含的深意!

 

继续以赛车car作为例子,假设现在你设计了“卡车”、“跑车”、“家用车”三种车,现在要增加一种车“卡丁车”,只要“卡丁车”也实现了“加速”、“刹车”、“转向”,那么player不需要修改代码,就可以玩“卡丁车”了;但如果你增加了一种“改装”的功能,那么player必须修改才能使用“改装”功能。

 

对应到代码上来说,OCP的应用原则如下:

1) 接口不变:包括函数名、函数参数、函数返回值等,可以应用OCP

2) 接口改变:已有函数修改名称、参数、返回值,或者增加新的函数,OCP都不再适应

 

虽然OCP原则是针对类设计提出来的原则,但其思想其实适应很广,系统和系统、子系统和子系统、模块和模块之间都可以应用OCP原则,而且不同的地方应用其实都是遵循同一个原则:通过接口交互!例如:

1) 类之间应用OCP:使用interface进行交互;

2)模块和模块、系统和系统:使用规定好的协议,不管是私有的还是公开的,例如HTTP、SOAP