ABP框架的基础配置及依赖注入讲解(2)

PersonAppService通过IPersonRepository调用CreatePerson方法,所以这方法依赖于IPersonRepository,代替了PersonRepository具体类。但PersonAppService(的构造函数)仍然依赖于PersonRepository。组件应该依赖于接口而不是实现。这就是所谓的依赖性倒置原则。
如果PersonAppService创建PersonRepository本身,它成为依赖IPersonRepository接口的具体实现,不能使用另一个实现。因此,此方式的将接口与实现分离变得毫无意义。硬依赖(hard-dependency)使得代码紧密耦合和较低的可重用。
我们可能需要在未来改变创建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); } }

PersonRepositoryFactory是一个静态类,创建并返回一个IPersonRepository。这就是所谓的服务定位器模式。以上依赖问题得到解决,因为PersonAppService不需要创建一个IPersonRepository的实现的对象,这个对象取决于PersonRepositoryFactory的Create方法。但是,仍然存在一些问题:

此时,PersonAppService取决于PersonRepositoryFactory。这是更容易接受,但仍有一个硬依赖(hard-dependency)。
为每个库或每个依赖项乏味的写一个工厂类/方法。
测试性依然不好,由于很难使得PersonAppService使用mock实现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); } }

这被称为构造函数注入。现在,PersonAppService不知道哪些类实现IPersonRepository以及如何创建它。谁需要使用PersonAppService,首先创建一个IPersonRepository PersonAppService并将其传递给构造函数,如下所示:

var repository = new PersonRepository(); var personService = new PersonAppService(repository); personService.CreatePerson("Yunus Emre", 19);

构造函数注入是一个完美的方法,使一个类独立创建依赖对象。但是,上面的代码有一些问题:

创建一个PersonAppService变得困难。想想如果它有4个依赖,我们必须创建这四个依赖对象,并将它们传递到构造函数PersonAppService。
从属类可能有其他依赖项(在这里,PersonRepository可能有依赖关系)。所以,我们必须创建PersonAppService的所有依赖项,所有依赖项的依赖关系等等. .如此,依赖关系使得我们创建一个对象变得过于复杂了。
幸运的是,依赖注入框架自动化管理依赖关系。

属性注入

构造函数注入模式是一个完美的提供类的依赖关系的方式。通过这种方式,您不能创建类的实例,而不提供依赖项。它也是一个强大的方式显式地声明是什么类的需求正确地工作。

但是,在某些情况下,该类依赖于另一个类,但也可以没有它。这通常是适用于横切关注点(如日志记录)。一个类可以没有工作日志,但它可以写日志如果你提供一个日志对象。在这种情况下,您可以定义依赖为公共属性,而不是让他们放在构造函数。想想,如果我们想在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!"); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wjypzf.html