持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
依赖注入
依赖注入,是指类之间依赖关系,通过注入的方式而不是通过使用 new 一个对象然后使用。
Class AObj {
public void do(){
BObj b = new BObj();
b.do();
}
}
// 通过构造函数注入
class AObj{
BObj b;
public AObj(BObj b){
this.b=b;
}
public void do(){
b.do();
}
}
AObj 类中使用了 BObj 类,一般情况下,在AObj 类的方法Do 使用了 BObj 类,基本都是通过 new 一个对象然后使用。如果有多个类就可能需要实例化多次,不仅维护不方便而且也会浪费资源不断的去实例化。
以上代码通过使用构造函数注入的方式解决了对依赖的类的使用,这样就没不用每次调用一次方法就实例化一次。依赖注入的方式还有其他种,比如:方法属性注入,属性 set 方法注入,接口注入。
AutoFac
现有很多实现依赖注入的第三方类库,可以很好帮助你实现对象之间的解耦工作。Autofac 是比较流行的 IOC 容器。其支持属性注入和方法注入,还支持 AOP 功能。更多详细的介绍和使用可查看官网。
基本用法
//创建一个容器建造者
ContainerBuilder cb = new ContainerBuilder();
// 注册普通类
cb.RegisterType<ClassA>();
// build下得到容器
IContainer cc = cb.Builder();
//基于容器获取对象实例
ClassA aobj = cc.Resolve<ClassA>();
注册类型有三种:
// 第一种:注册普通类
cb.RegisterType<ClassA>();
// 第二种:注册抽象和实现
cb.Register<ClassA>().As<IA>()
// 第三种:直接注册实例
cb.ResgiterInstance(new AClass())
// 第四种:注册程序集
builder.RegisterAssemblyTypes(classAssembly);
作为一个项目的 IOC 支持,我使用的时候是使用程序集的方式进行注册。因为它支持以接口的方式进行注册 AsImplementedInterfaces(),顶层调用只需关注接口无需关注具体实现,很好的体现解耦。所以将接口注册到IOC 中。
程序集的方式还支持条件类型的注册 Where() ,可以过滤掉不需要依赖的注入的类。
cb.RegisterAssemblyTypes(程序集数组),程序集必须是public的
.AsImplementedInterfaces():表示注册的类型,以接口的方式注册
.PropertiesAutowired():支持属性注入
.Where:满足条件类型注册
对象的声明周期
注册到 IOC 中的类,还可以根据属性指定创建出来的对象的声明周期:
- 每次获取都是新的实例 ,使用 InstancePerDependency(),其也是 Autofac 的默认设置。
- 同一个进程内是同一个实例,就是单例的。使用 SingInstance() 方法
- 同一个作用域内是同一个实例,使用 InstancePerLifetimeScope()方法
- 在作用域范围里面,同一个作用域下面的对象是同一个,在作用域范围外无法创建实例,使用
InstancePerMatchingLifetimeScope()
方法 - 一次请求同一个对象 InstancePerRequest方法
总结
依赖注入可以很好的对类进行解耦。松耦合,方便开发测试。在软件设计原理说到:“上层模块不应依赖于底层模块,应当依赖于抽象,而不应依赖于细节”。其实就是在说解耦,顶层模块通过接口得到对应的具体实现,而上层无需关心底下的具体实现的东西,只需知道该接口就可以。