(译)ABP之依赖注入
原文地址:https://aspnetboilerplate.com/Pages/Documents/Dependency-Injection
- 什么是依赖注入
- 传统方式的问题
- 解决方案
- 构造函数注入
- 属性注入
- 依赖注入框架
- ABP依赖注入基础设施
- 注册依赖项
- 常用注册
- 帮助接口
- 自定义/直接注册
- 使用IocManager
- 解析
- 构造函数&属性注入
- IIocResolver, IIocManager and IScopedIocResolver
- 附加部分
- IShouldInitialize 接口
- ASP.NET MVC & ASP.NET Web API 集成
- ASP.NET Core 集成
- 最后备注
什么是依赖注入
传统方式的问题
public class PersonAppService
{
private IPersonRepository _personRepository; public PersonAppService()
{
_personRepository = new PersonRepository();
} public void CreatePerson(string name, int age)
{
var person = new Person { Name = name, Age = age };
_personRepository.Insert(person);
}
}
- PersonAppService在CreatePerson方法里使用了IPersonRepository的引用,所以这个方法依赖于IPersonRepository,而不是依赖于PersonRepository,但是,在PersonAppService的构造函数中依然依赖于PersonRepository。组件应该依赖于接口而不是实现类。这就是依赖反转原则。
- 如果PersonAppService创建PersonRepository本身,这样就变成了依赖IPersonRepository接口具体的实现类了,同时使得它不能用IPersonRepository接口的其它实现类,这样,将接口与实现类分离就毫无意义了。强依赖关系使得代码基础紧密耦合,且可重用性较低。
- 我们在以后可能需要改变PersonRepository的创建,比如说,我们可能想把它创建成一个单例(单一共享一个实例,而不是每次用时都创建一个对象),或者我们可能想创建多个IPersonRepository接口的实现类,而我们是根据条件来创建其中某个实现类的实例。在这种情况下,我们就得修改所有依赖于IPersonRepository接口的类。
- 有了这样的依赖关系,我们是很难(或者不可能)对PersonAppService进行单元测试。
public class PersonAppService
{
private IPersonRepository _personRepository; public PersonAppService()
{
_personRepository = PersonRepositoryFactory.Create();
} public void CreatePerson(string name, int age)
{
var person = new Person { Name = name, Age = age };
_personRepository.Insert(person);
}
}
- 这次,PersonAppService 依赖于PersonRepositoryFactory ,这个相当来说还可以接受,但是这样还是一种强依赖关系。
- 为每一个repository 或它的依赖类写一个工厂类或方法是很乏味的。
- 这样可测试性还是不好,因为很难让PersonAppService 去使用一些模拟实现IPersonRepository的对象。
解决方案
构造函数注入模式
public class PersonAppService
{
private IPersonRepository _personRepository; public PersonAppService(IPersonRepository personRepository)
{
_personRepository = personRepository;
} public void CreatePerson(string name, int age)
{
var person = new Person { Name = name, Age = age };
_personRepository.Insert(person);
}
}
var repository = new PersonRepository();
var personService = new PersonAppService(repository);
personService.CreatePerson("Yunus Emre", );
- 创建一个PersonAppService 对象变得更难了。试想一下,如果PersonAppService 依赖于4个类,那我们就必须创建这4个依赖类的对象,并把它们传递给PersonAppService 的构造函数。
- 依赖类可能也有它们自己的依赖类(这里,PersonRepository可能还依赖其它的类),因此,我们必须创建所有PersonAppService 所依赖的对象,以及这些依赖对象所依赖类的对象,如此等等。这样,我们甚至连一个对象都创建不了了,因为这依赖关系它复杂了。
属性注入模式
public class PersonAppService
{
public ILogger Logger { get; set; } private IPersonRepository _personRepository; public PersonAppService(IPersonRepository personRepository)
{
_personRepository = personRepository;
Logger = NullLogger.Instance;
} public void CreatePerson(string name, int age)
{
Logger.Debug("Inserting a new person to database with name = " + name);
var person = new Person { Name = name, Age = age };
_personRepository.Insert(person);
Logger.Debug("Successfully inserted!");
}
}
var personService = new PersonAppService(new PersonRepository());
personService.Logger = new Log4NetLogger();
personService.CreatePerson("Yunus Emre", );
依赖注入框架
var container = new WindsorContainer(); container.Register(
Component.For<IPersonRepository>().ImplementedBy<PersonRepository>().LifestyleTransient(),
Component.For<IPersonAppService>().ImplementedBy<PersonAppService>().LifestyleTransient()
); var personService = container.Resolve<IPersonAppService>();
personService.CreatePerson("Yunus Emre", );
ABP依赖注入基础设施层
注册依赖项
常规注册
public interface IPersonAppService : IApplicationService
{
//...
} public class PersonAppService : IPersonAppService
{
//...
}
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
帮助接口
public interface IPersonManager
{
//...
} public class MyPersonManager : IPersonManager, ISingletonDependency
{
//...
}
自定义/直接注册
使用IocManager
IocManager.Register<IMyService, MyService>(DependencyLifeStyle.Transient);
使用Castle Windsor API
IocManager.IocContainer.Register(Classes.FromThisAssembly().BasedOn<IMySpecialInterface>().LifestylePerThread().WithServiceSelf());
更多信息,可以参考Windsor文档
解析
构造函数&属性注入
public class PersonAppService
{
public ILogger Logger { get; set; } private IPersonRepository _personRepository; public PersonAppService(IPersonRepository personRepository)
{
_personRepository = personRepository;
Logger = NullLogger.Instance;
} public void CreatePerson(string name, int age)
{
Logger.Debug("Inserting a new person to database with name = " + name);
var person = new Person { Name = name, Age = age };
_personRepository.Insert(person);
Logger.Debug("Successfully inserted!");
}
}
IIocResolver, IIocManager and IScopedIocResolver
public class MySampleClass : ITransientDependency
{
private readonly IIocResolver _iocResolver; public MySampleClass(IIocResolver iocResolver)
{
_iocResolver = iocResolver;
} public void DoIt()
{
//Resolving, using and releasing manually
var personService1 = _iocResolver.Resolve<PersonAppService>();
personService1.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });
_iocResolver.Release(personService1); //Resolving and using in a safe way
using (var personService2 = _iocResolver.ResolveAsDisposable<PersonAppService>())
{
personService2.Object.CreatePerson(new CreatePersonInput { Name = "Yunus", Surname = "Emre" });
}
}
}
using (var scope = _iocResolver.CreateScope())
{
var simpleObj1 = scope.Resolve<SimpleService1>();
var simpleObj2 = scope.Resolve<SimpleService2>();
//...
}
附加部分
IShouldInitialize 接口
ASP.NET MVC & ASP.NET Web API 集成
ASP.NET Core集成
最后备注
(译)ABP之依赖注入的更多相关文章
- ABP的依赖注入
目录 说说ABP的依赖注入 代码追踪 说说ABP的依赖注入 上篇abp运行机制分析分析了ABP在启动时,都做了那些事:这篇我们来说说ABP的最核心的一部分:依赖注入(DependencyInjecti ...
- ABP框架 - 依赖注入
文档目录 本节内容: 什么是依赖注入 传统方式的问题 解决方案 构造器注入模式 属性注入模式 依赖注入框架 ABP 依赖注入基础 注册依赖 约定注入 辅助接口 自定义/直接 注册 使用IocManag ...
- ABP之依赖注入
写在开头 ABP开源项目最近有点小火,还开展了线下活动.本着学习DDD的心态与学习开源代码的的好奇,我也看了一遍ABP源码,在此将自己学习ABP的一些心得记录下来. 作为核心的IoC 作为一种解耦的方 ...
- [译] 关于 Angular 依赖注入你需要知道的
如果你之前没有深入了解 Angular 依赖注入系统,那你现在可能认为 Angular 程序内的根注入器包含所有合并的服务提供商,每一个组件都有它自己的注入器,延迟加载模块有它自己的注入器. 但是,仅 ...
- Asp.Net Core 3.1 Api 集成Abp项目依赖注入
Abp 框架 地址https://aspnetboilerplate.com/ 我们下面来看如何在自己的项目中集成abp的功能 我们新建core 3.1 API项目和一个core类库 然后 两个项目都 ...
- ABP(现代ASP.NET样板开发框架)系列之6、ABP依赖注入
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...
- ABP源码分析六:依赖注入的实现
ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...
- ABP理论学习之依赖注入
返回总目录 本篇目录 什么是依赖注入 传统方式产生的问题 解决办法 依赖注入框架 ABP中的依赖注入基础设施 注册 解析 其他 ASP.NET MVC和ASP.NET Web API集成 最后提示 什 ...
- ABP依赖注入
ABP依赖注入 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之6.ABP依赖注入 ABP是“ASP.NET Boilerplate Project (ASP.N ...
随机推荐
- Java反射机制(Reflect)解析
一.导读 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言的设计 ...
- component及刚体rigidbody用法
关于getcomponent函数,rigidbody(2d)的嵌套关系及用法 1.getcomponent函数 在unity中脚本可以看成是可定义的组件,我们经常要访问同一对象或不同对象中的脚本,可以 ...
- 【HDFS】相关概念及常用命令
本文用于记录Hadoop中HDFS相关概念以及常用命令,以便日后查询. 概念之间无先后顺序,只是用于记录. 参考的Hadoop的版本是2.7.3 1. 角色 hadoop fs [hdfs dfs] ...
- common lisp和scheme的区别
1. 在Common Lisp 眼中,一个符号的symbol-value 和symbol-function 是不一样的,而Scheme对两者不作区分.在Scheme 里面,变量只有唯一对应的值,它可以 ...
- 轻松学会ES6新特性之生成器
生成器虽然是ES6最具魔性的新特性,但也是最难懂得的一节,笔者写了大量的实例来具体化这种抽象的概念,能够让人一看就懂,目的是希望别人不要重复或者减少笔者学习生成器的痛苦经历. 在说具体的ES6生成器之 ...
- PyQt中对RadioButton分组
我们知道在同一widget组件中的radio button有排他属性,为了在一个窗口中显示多组radio button,我们需要对其分组. 通常有两种选择,一种是BoxGroup,另一种是Button ...
- RSA加密算法验证(C#实现)
RSA算法简单原理介绍(节选于网络) 假设Alice想要通过一个不可靠的媒体接收Bob的一条私人讯息.她可以用以下的方式来产生一个公钥和一个私钥: 随意选择两个大的质数p和q,p不等于q,计算N=pq ...
- Code Lock
Code Lock Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others) Total Su ...
- Pseudoforest(伪最大生成树)
Pseudoforest Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total ...
- Hacker Rank: Kingdom Division 不完全报告
原题链接: Kingdom Division 由于树的层次可能很深,所以这里不能使用递归版的DFS.我使用了BFS. BFS确定各结点的父结点和它的孩子数. 用逆拓扑排序确定结点的计算顺序. same ...