您的位置:首页 > 编程语言

那些年搞不懂的高深术语——依赖倒置•控制反转•依赖注入•面向接口编程

2016-05-22 20:40 381 查看
那些年,空气中仿佛还能闻到汉唐盛世的余韵,因此你决不允许自己的脸上有油光,时刻保持活力。然而,你一定曾为这些“高深术语”感到过困扰。也许时至今日,你仍对它们一知半解。不过就在今天,这一切都将彻底改变!我将带领你以一种全新的高清视角进入奇妙的编程世界,领略涵泳在这些“高深术语”中的活泼泼的地气,以及翩跹于青萍之末的云水禅心。

class CustomizeHandler: ICustomizeHandler
{
public void HandleInformation(string sourceUserID, int informationType, byte[] info)
{
······
}

public byte[] HandleQuery(string sourceUserID, int informationType, byte[] info)
{
······
}
}

IRapidPassiveEngine rapidPassiveEngine = ESPlus.Rapid.RapidEngineFactory.CreatePassiveEngine();
CustomizeHandler customizeHandler = new CustomizeHandler();
rapidPassiveEngine.Initialize("ID", "passWord", "127.0.0.1", 9000, customizeHandler);


View Code
很明显,相比于上一个例子,这里的依赖关系变成了rapidPassiveEngine依赖于customizeHandler,也就是说依赖关系倒置了过来,上层模块不再依赖于底层模块,而是它们共同依赖于抽象。rapidPassiveEngine依赖的是IcustomizeHandler接口类型的参数,customizeHandler同样是以实现的接口的方式依赖于IcustomizeHandler——这就是一个依赖倒置的典范。

·控制反转(Inversion of Control)

控制反转跟依赖倒置是如出一辙的两个概念,当存在依赖倒置的时候往往也存在着控制反转。但是控制反转也有自己的独特内涵。

首先我们要区分两个角色,server 跟 Client,也就是服务方和客户方。提供服务端的一方称为服务方,请求服务的一方称为客户方。我们最熟悉的例子就是分布式应用的C/S架构,服务端和客户端。其实除此之外,C/S关系处处可见。比如在TCP/IP协议栈中,我们知道,每层协议为上一层提供服务,那么这里就是一个C/S关系。当我们使用开发框架时,开发框架就是作为服务方,而我们自己编写的业务应用就是客户方。当Client调用server时,这个叫做一般的控制;而当server调用Client时,就是我们所说的控制反转,同时我们也将这个调用称为“回调”。控制反转跟依赖倒置都是一种编程思想,依赖倒置着眼于调用的形式,而控制反转则着眼于程序流程的控制权。一般来说,程序的控制权属于Client,而一旦控制权交到server,就叫控制反转。比如你去下馆子,你是Client餐馆是server。你点菜,餐馆负责做菜,程序流程的控制权属于Client;而如果你去自助餐厅,程序流程的控制权就转到server了,也就是控制反转。

控制反转的思想体现在诸多领域。比如事件的发布/ 订阅就是一种控制反转,GOF设计模式中也多处体现了控制反转,比如典型的模板方法模式等。而开发框架则是控制反转思想应用的集中体现。比如之前所举的ESFramework通信框架的例子,通信引擎回调用户自定义的消息处理器,这就是一个控制反转。以及ESFramework回调用户自定义的群组关系和好友关系,回调用户自定义的用户管理器以管理在线用户相关状态,回调用户自定义的登陆验证处理,等等不一而足。再比如与ESFramework一脉相承的轻量级通信引擎StriveEngine,通过回调用户自定义的通信协议来实现更加灵活的通信。



由此我们也可以总结出开发框架与类库的区别:使用开发框架时,框架掌握程序流程的控制权,而使用类库时,则是应用程序掌握程序流程的控制权。或者说,使用框架时,程序的主循环位于框架中,而使用类库时,程序的主循环位于应用程序之中。框架会回调应用程序,而类库则不会回调应用程序。ESFramework和StriveEngine中最主要的对象都以engine来命名,我们也可以看出框架对于程序主循环的控制——它会为你把握方向、眼看前方、轻松驾驭!

·依赖注入(Dependency Injection)

  依赖注入与依赖倒置、控制反转的关系仍旧是一本万殊。依赖注入,就其广义而言,即是通过“注入”的方式,来获得依赖。我们知道,A对象依赖于B对象,等价于A对象内部存在对B对象的“调用”,而前提是A对象内部拿到了B对象的引用。B对象的引用的来源无非有以下几种:A对象内部创建(无论是作为字段还是作为临时变量)、构造器注入、属性注入、方法注入。后面三种方式统称为“依赖注入”,而第一种方式我也生造了一个名词,称为“依赖内生”,二者根本的差异即在于,我所依赖的对象的创建工作是否由我自己来完成。当然,这个是广义的依赖注入的概念,而我们一般不会这样来使用。我们通常使用的,是依赖注入的狭义的概念。不过,直接陈述其定义可能会过于诘屈聱牙,我们还是从具体的例子来看。  

   


  比如OMCS网络语音视频框架,它实现了多媒体设备(麦克风、摄像头、桌面、电子白板)的采集、编码、网络传送、解码、播放(或显示)等相关的一整套流程,可以快速地开发出视频聊天系统、视频会议系统、远程医疗系统、远程教育系统、网络监控系统等等基于网络多媒体的应用系统。然而,OMCS直接支持的是通用的语音视频设备,而在某些系统中,需要使用网络摄像头或者特殊的视频采集卡作为视频源,或者其它的声音采集设备作为音频源,OMCS则提供了扩展接口——用户自己实现这个扩展的接口,然后以“依赖注入”的方式将对象实例注入到OMCS中,从而完成对音、视频设备的扩展。扩展方法详情参考

“依赖注入”常常用于扩展,尤其是在开发框架的设计中。从某种意义上来说,任何开发框架,天生都是不完整的应用程序。因此,一个优秀的开发框架,不仅要让开发者能够重用这些久经考验的的卓越的解决方案,也要让开发者能够向框架中插入自定义的业务逻辑,从而灵活自由地适应特定的业务场景的需要——也就是说要具备良好的可扩展性。比如上面提到的OMCS网络语音视频框架可应用于音、视频聊天系统、视频会议系统、远程医疗系统、远程教育系统、网络监控系统等等基于网络多媒体的应用系统;以及ESFramework通信框架能够应用于即时通讯系统,大型多人在线游戏、在线网页游戏、文件传送系统、数据采集系统、分布式OA系统等任何需要分布式通信的软件系统中——这种良好的扩展性都与“依赖注入”的使用密不可分!

·面向接口编程

谈到最后,“面向接口编程”已经是呼之欲出。无论是依赖倒置、控制反转、还是依赖注入,都已经蕴含着“面向接口编程”的思想。面向接口,就意味着面向抽象。作为哲学范畴而言,规定性少称为抽象,规定性多称为具体。而接口,就是程序中的一种典型的“抽象”的形式。面向抽象,就意味着面向事物的本质规定性,摆脱感性杂多的牵绊,从而把握住“必然”——而这本身就意味着自由,因为自由就是对必然的认识。

也许以上的这段论述太过“哲学”,但是“一本之理”与“万殊之理”本身就“体用不二”——总结来看,依赖倒置、控制反转、依赖注入都围绕着“解耦和”的问题,而同时自始至终又都是“面向接口编程”的方法——因此,“面向接口编程”天生就是“解耦和”的好办法。由此也印证了从“抽象”到“自由”的这一段范畴的辩证衍化。

“面向对象”与“面向接口”并非两种不同的方法学,“面向接口”其实是“面向对象”的内在要求,是其一部分内涵的集中表述。我们对于理想软件的期待常被概括为“高内聚,低耦合”,这也是整个现代软件开发方法学所追求的目标。面向对象方法学作为现代软件开发方法学的代表,本身就蕴含着“高内聚,低耦合”的思想精髓,从这个意义上来说,“面向对象”这个表述更加侧重于“高内聚”,“面向接口”的表述则更加侧重于“低耦合”——不过是同一事物的不同侧面罢了。

除此之外,我们也能从“面向接口编程”的思想中得到“世俗”的启迪——《论语》里面讲,不患无位,患所以立;不患人之不己知,患其不能也——就是教导我们要面向“我有没有的本事?”、“我有没有能力?”这样的接口,而不是面向“我有没有搞到位子?”、“别人了不了解我?”这样的具体。依我看,这是莫大的教诲!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: