Ioc(Inversion of Control)或者叫依赖注入DI(Dependency Injection)
如果一个接口有两个实现类,但是在实现过程中,用到了这两个具体的实现类。
如果采用IOC,则只能是注册一个接口类型,那么如何确保IOC在合适的时候传入不同类的实例?这是我突然间想到的一个问题,希望园友们可以帮忙解答一下!
所谓IOC(控制反转)或者说是依赖注入,就是将你设计好的类交给系统去控制,而不是在你的类内部控制,控制权发生了变化,就称为控制反转。
IOC的使用时机就是在一个接口有多个实现类的情况下,并且还可能存在扩展这个接口的可能性的情况下使用我个人觉得是最好的。
我们使用抽象接口来隔离使用者和具体实现类之间的依赖?谁依赖谁呢?我们要清楚的明白这个关系才能更好的明白如何使用IOC。我以为是使用者依赖具体的实现。
IOC表示的是依赖注入,但是这个表示谁依赖谁呢?
Class A
{
IB _b;
public A()
{
_b=new ImpB();//在调用实现类的ImpB中方法 定义一个该类型的变量 采用接口定义方式 ,这个采用接口定义的方式,可以用来叫做面向接口的编程,这个在现在也是一种很常用的方式。不采用面向抽象编程而是采用面向接口编程。
}
}
Class ImpB:IB
{
//具体的实现类
}
class ImpC:IB
{
//C具体的实现
}
但是如果采用IOC方式,只需要在A的构造函数中传入必须的参数。这就会出现上面我提到的两个实现类的问题。
还有我还要提出一个问题,一个实现类继承自两个接口,那么如何进行值的注入呢?
关于IOC的几个概念:
服务: 组件 自动装配
所谓服务,就是一系列的接口,接口约定了服务,从而使随意的更换实现接口的具体实现不会对使用该服务的代码进行任何的更改。面向服务的编程 ==面向接口的编程?
组件:组件是一个可重用的程序单元,是实现了某个具体接口并且仅仅实现了该接口的实现类。组件是实现了某个服务接口的类。
具体的实现类。
自动装配(Auto Wiring):指的是由容器自动管理组件之间的依赖关系。自动在需要具体实现的时候通过某种注入方式注入需要的实例。
IOc也属于一种设计模式,它主要是用来协调各个组件之间的组合关系。增加了程序的可迁移性以及良好的组件解耦。不需要在实现类中使用new 来实例化对象,避免了组件类之间的耦合,也避免了在需要更改具体时候的时候更改程序的内部代码实现。
IOC很好的解决了这个问题,它把组件之间的关系由程序内部提到外部容器来管理,也就是说由容器在运行期间将组件间的依赖关系动态的注入组件中。
控制程序间关系的实现交给了外部容器来管理,这就是所谓的好莱坞法则。不要找我,我会找你。
下面还有一个要注意的就是关注点分类(SOC),这应该算是IOC的最初的目的,实现关注点的分离,通过分解程序,把程序分解成一个个的功能点,然后确保每个功能点都是没有相互直接联系的。这就是关注点分离原则。在IOC将控制权转移到自己手上的时候其实就是就是解除了组件之间的实际依赖关系,解除了组件(也就是实现类)直接的直接耦合。实现了基本的关注点分离原则。
还有一个设计原则叫做面向切面的编程原则(AOP),这种方式是纵向的看待程序功能。
我个人认为IOC是一个理论,这DI则是具体实现方式,
现在我来提一个问题?为什么我们必须要在application_start方法中注册autofac或ioc,以便进行组件解耦?
答:我们知道无论是asp.net web form还是MVC,最终都是运行在.Net framework 之上,通过IIS控制从页面请求到页面响应的整个过程。每个请求从进入到最后响应(暂且称为声明周期)都是被asp.net 工作者进程把持,因为我们无法直接的控制该进程,所以我们想在整个生命周期内进行注入的可能性基本上就不存在。既然这样,我们就只能是在生命周期开始之前就进行注入。在一个请求从进入到响应会经过IIS的很多处理,其中IhttpModule 管线就可以被我们使用来进行依赖注入。这也就解释了为什么我们只能在程序启动之前注册。
Autofac是在IOC理论下和C#紧密结合的一个框架,它提供了相对其他框架所不可比拟的优势:
1.使用C#泛型
2.可以方便的注册Asp.net MVC Controller
3.支持C# lambda表达式,以及对linq的完美支持
4.具有无侵入性,可以在运行时对对象的实例以及声明周期进行管理
5.轻量级的框架
Autofac的简单使用:
1.注册类型的简单,无需任何xml配置就可以使autofac正常运行。当然autofac也可以通过xml配置文件进行配置。
public void ApplicationStart()
{
var builder=new ContainerBuilder();//创建autofac管理注册类的容器实例
//下面就需要为这个容器注册它可以管理的类型
//builder.Register... builder的register方法可以通过多种方式注册类型
//其实register这些方法我们有必要详细的了解一下,毕竟每种方法都可以找到针对的使用地方
//builder.Build();//生成具体的实例
//下面就是使用MVC的扩展 更改注入方式
var container=builder.Build();
DependencyResolver.SetResolver(new Autofac.Integration.Mvc.AutofacDependencyResolver(container));//更改了MVC中的注入方式
}
2.在homeController中使用构造函数注入
public class HomeController
{
private Inet _net;
public HomeController(Inet net)//接口定义 构造函数注入
{
_net=net; //我们在运行时通过单步调试就可以看到net其实就是我们实现接口Inet的具体实例。前提是已经正确注册了autofac并且正确的进行配置
}
public ActionResult()
{
var result=_net.GetAll();//调用具体类的具体方法返回结果
return view(result); //进行值的传递
}
}
这样我们就可以在项目中使用autofac作为组件来管理我们的程序,进行控制权的转移。
总结一下,IOC本质上就是使用户的控制权转移到单独的组件上(autofac),通过各种方式的注入来达到组件之间的解耦,实现关注点分离的效果。
autofac的使用非常简单,我就不再举例说明,我只是说明了IOC的使用背景。
我没有看过autofac的源代码,不知道我的认识是不是正确,如果有错误,请你指出来,我会积极改正,谢谢。
还有IOC只是一种手段,不是目的,不是我们设计架构时应该考虑的事情,这只是我们在实现时采用的技巧,当然也有其他方法可以达到类似的效果,也有很多这样的组件可以达到这个效果。我们的最终目的是实现关注点的分离以及组件之间的耦合度最低。