控制反转IoC(Invers of Control)

  • 控制反转IoC(Invers of Control)已关闭评论
  • 182 次浏览
  • A+
所属分类:.NET技术
摘要

控制反转,即IoC(Invers of Control),它并不是属于某个特定编程语言的技术,本质上它是设计框架的一种基本思想。ASP.NET Core中的依赖注入其实就是结合了控制反转的思想所设计出的一套框架。所以为了更好掌握依赖注入,我们就必须先对控制反转有一个初步的认识。控制反转实际上是一种“控制权的转移”的体现,下面通过一个例子来看看它是怎么体现“控制权的转移”这回事的。

1.反转的体现

控制反转,即IoC(Invers of Control),它并不是属于某个特定编程语言的技术,本质上它是设计框架的一种基本思想。ASP.NET Core中的依赖注入其实就是结合了控制反转的思想所设计出的一套框架。所以为了更好掌握依赖注入,我们就必须先对控制反转有一个初步的认识。控制反转实际上是一种“控制权的转移”的体现,下面通过一个例子来看看它是怎么体现“控制权的转移”这回事的。

我们通常在日常生活中,用餐这件事是必不可少的,并且实际的用餐权掌握在我们自己手中,所以由我们自己决定什么时候用餐,用餐时吃什么食物。当有一天你生病了,于是你的父母因为要照料你,此时会由他们决定你每天什么时间用餐,具体吃什么。这个时候控制权(用餐权)就发生了转移,控制权(用餐权)由你转移到了你父母那里了。

那么我们在回到软件设计当中来,控制反转中的控制权实际上就是针对某个任务的流程控制,而“控制权的转移”实际上就是将应用程序中对流程的控制转移到框架中。在初步了解控制反转控制的是什么,以及反转的双方是谁后,其实从表面上我们还是很难明白其中的含义,为什么要实现控制反转?不实现控制反转会怎么样?


2.不实现控制反转的例子

接下来我们通过一个实例来看看,如果应用程序中的某个流程不实现控制反转,会对应用程序带来什么样的问题。假设ASP.NET框架没有为我们提供MVC处理HTTP请求的流程,只是提供了一个类库并将处理流程的方法包含在名为MvcLib的类中。其中处理各个流程的方法如下代码:

1 public  class MvcLib 2 { 3     public static void Listen(Url address); 4     public static Request Receive(); 5     public static Controller CreateController(Request request); 6     public static View ExecuteController(Controller controller); 7     public static void RenderView(View view); 8 }

在这个例子中,由于ASP.NET框架没有提供MVC处理HTTP请求的流程,所以我们不得不在应用程序中自行设计使用流程,基于MVC的思想我们将处理流程的处理设计如下图:

 控制反转IoC(Invers of Control)

在设计好MVC的流程后,我们使用框架提供的类库方法,自行调用实现MVC处理HTTP请求的机制,代码如下:

 1 while(true)  2 {  3     var address=new Uri("http://0.0.0.0:8080");  4     MvcLib.ListenAsync(address);  5     while(true)  6     {  7         var request=MvcLib.ReceiveAsync();  8         var controller=MvcLib.CreateController(request);  9         var view=MvcLib.ExecuteController(controller); 10         MvcLib.RenderView(view); 11     } 12 }

上面的示例就是一个框架没有实现控制反转的例子,导致流程的控制权在应用程序当中。这个例子中的ASP.NET框架,提供的MvcLib类仅仅是提供了各个流程环节的实现方法,ASP.NET框架没有为我们制定MVC的流程实现,作为该类的消费者的应用程序,必须要自行编排MVC的工作流程,这无疑对应用程序本身来了一定程度的复杂性,如果流程的复杂程度高,编排流程出错的风险也会随之提高。

另外,对于MVC的处理流程通常是属于比较典型的、广泛化的需求。所以对于其他的ASP.NET应用程序也会使用到同样的流程编排方式,那么这就意味着编排整个MVC工作流程的代码并没有得到复用。


3.框架和类库

在真实开发场景下,我们需要的不是一个仅仅能够提供单一程序功能的类库,而是能够直接在上面构建应用的框架,所以为了让框架不沦落成类库,控制反转是框架所采用的一种基本的设计思想、原则。

类库和框架的不同之处在于,前者往往只是提供实现某种单一功能的API,而后者针对一个目标任务对这些单一功能进行编排,以形成一个完整的流程,并利用一个引擎驱动这个流程自动运转。

类库和框架的不同之处在于,类库往往通过组件的形式为实现某个功能提供相应的API,而框架可以为某个常用的任务制定流程并对其环节进行编排,以便形成一个完整易用的流程提供给应用程序使用。

虽然如今框架和类库是我们构建应用程序密不可分的东西,但是在传统面向类库编程的时代,大多数任务处理的流程都在应用程序放进行控制,在逐渐引入框架的开发方式后,任务处理的流程控制权才都被转移到框架中。


4.ASP.NET Core中的控制反转

上文对控制反转的含义做了明确的解释:即将一组流程的控制从应用程序中转移到框架之中。个人觉得这个解释比较偏宏观,更加偏向设计思想层面的一种解释。而对于在ASP.NET Core中的控制反转最直观的一种解释就是:将创建对象的控制权从应用程序转移到了ASP.NET Core的依赖注入框架。

在ASP.NET Core中最直观的一种感受就是:“从原来自己创建对象”,变成“自己不用创建对象,告诉别人需要什么对象,别人主动提供对象”。如果在你没有理解控制反转和依赖注入这些概念,去接触一个使用了依赖注入的项目,你把代码翻个底朝天都找不到对象的实例在哪里创建的,因为这创建对象这件事不在我们的应用程序中了,而是在ASP.NET Core的依赖注入框架(Dependency Injection)

解耦

ASP.NET Core借鉴控制反转的思想设计出了依赖注入框架,带给应用程序最大的一个好处就是“解耦”。

实际上我们开发的ASP.NET Core应用程序,本质上就是通过各个类的对象相互协作而构建的,某些复杂的功能也是通过调用各个类的对象,从而组成的流程体系,比如你点击付款功能,这背后可能就有:订单类、商品类、支付类等各个类协作实现功能。在这种背景下每个类都会直接或间接的产生依赖的关系,通过依赖注入可以实现一定程度的“解耦”,从而使应用程序能够更好的适应需求的变化。

主动到被动

ASP.NET Core这种控制反转的形式,比较类似于我们现在社会上企业的一种用人体制。通常企业都是主动发布招聘信息,并且直接和员工签署合同。随着企业的长期经营,企业发现这种传统的用人方式存在某些问题:1.岗位需求量大了后,如果每名员工都是企业直属的,将会增加很大的开销;2.某些岗位的流动性大,很会因为某些因素导致人员大量流失,会经常出现招聘不及时,无法填补工作空缺,或工作新旧交接出现问题。

“资本终归是资本”,企业为了追求利益最大化,采取了一种新的用人制度,那就是我们通常说的“外包”,将员工的招聘交给第三方劳务公司,企业不在负责招聘只用专注业务和生产,上面的问题企业都不在担心,第三方劳务公司会源源不断的为企业主动提供员工。

这以社会现象其实就和我们ASP.NET Core这种控制反转有着异曲同工之妙,只不过企业是在损人利己,而对框架而言是在追求更好的程序设计。

公司不在主动招聘员工,而是告知用人需求给第三方劳务公司后,由他们主动提供员工,这个现象就类似我们ASP.NET Core控制反转的概念一样,应用程序无需自己创建对象,只用将对象的需求告诉给框架,在使用时候框架将会主动提供。


5.结语

本文对Ioc控制反转的概念从两个方面进行了解释,一种是基于框架思想层面,另一种是在ASP.NET Core中的运用体现。可能两个方面在印证上存在一些差异,但总体来说,最终的目的都是:是提高了框架的可用性且减轻应用程序的复杂性。

控制反转的思想在框架上的运用体现不光局限在本义上(应用程序对流程控制权转移到框架),其中很有很多细节,本文不在此一一阐述,例如这其中还有:在反转后应用程序的代码于框架直接采用“好莱坞法则”进行交互、框架的流程为应用程序开放环节的定制化等等。

总体而言,在一个基于控制反转思想的框架上进行应用开发,就相当于在一条调试好的流水线上生产某种产品。我们只需要在相应的环节准备对应的原材料,最终依赖于流水线的标准化、自动化的处理流程,我们就能得到相应的产品。