ASP.NET Core的框架的设计从头到尾都是模块化的,并且遵循良好的软件工程实践。在面向对象的程序设计中,SOLID经受住了时间的考验。ASP.NET Core已经把依赖注入融入了核心框架。不管你自己是否想把依赖注入运用到自己的代码中,ASP.NET Core框架已经把依赖注入当成了一个基本概念。
SOLID是 Single responsibility, Open-closed, Liskov substitution, Interface segregation, Dependeny inversion的简写:https://zh.wikipedia.org/zh-hans/SOLID_(面向对象设计)
依赖注入的介绍参考链接:https://www.martinfowler.com/articles/injection.html
1.明白依赖注入的好处
在简单应用程序中我们使用不到依赖注入,但当应用程序变得复杂得时候,依赖注入(DI)可以作为一个伟大的工具来控制代码的复杂性。
让我们看下面一个例子,当不使用DI时,一个用户在你的Web应用程序上注册后,你想给它发送一封邮件,下面的代码展示了你可能会在最初的时候这样处理问题。
在这个例子中,当一个新用户注册你的Web应用程序时,在UserControllor中RegeditUser
将执行。首先创建一个EmailSender类的实例,并且调用SendEmail()方法去发送邮件。在这个例子中,你可以设想将看到以下的内容:
Console.WriteLine将会执行发送email。
如果EmailSender类像这个例子一样简单并且没有依赖项,你可能不会考虑使用其它方法来创建对象。在某种程度上,你可能时对的。但是如果你稍后更新EmailSender的实现逻辑,发现它并不能实现自身邮件发送的全部逻辑。
实际上,EmailSender在发送邮件时需要做大量的事情:
1.创建一个email消息
2.配置email服务的设置
3.将邮件发送给emial服务器
如果在一个类中实现以上功能,将会违背单位职责原则(SRP),所以不能让EmialSender依赖其它服务。下图将会展示Web应用程序的依赖将会是怎样的。UserController想要使用EmailSender去发送邮件,但是如果要这样做,首先需要创建一个MessageFactory,NetworkClient,EmailServerSettings对象给EmailSender提供依赖。
每一个类都需要大量的依赖,在这个例子中UserController作为“底部”的类,需要知道如何创建它所依赖的每一个类,以及每一个类的依赖关系。
多依赖服务的例子如下:
NetworkClient依赖的实例代码如下:
用这样的方式可能觉得很麻烦,但这样的依赖链却是很常见的。实际上,你的代码中并没有这样写,那你的类将会很庞大,并且违背了单一职责原则。当你手动创建依赖时,发送邮件时是没有DI的。代码如下所示:
上述代码示例变成了一些粗糙的代码。当在UserController调用时,为提高EmailSender的设计性,以分离出不同的职责,这成为了一个麻烦事。上述代码有以下问题。
1.没有遵循单一职责原则-我们的代码同时负责创建EmailSender实例并且使用它发送邮件。
2.相当大的方法代码-上面的RegeditUser方法,只有最后两行代码才有用。很难读懂这个方法的真正目的是什么。
3.与实现绑定-如果你决定去重构EmialSender并且去添加另一个依赖,你需要去更新它每一个使用的地方。
UserController已经明确的依赖了EmailSender类,并且手动创建了这个对象的实例作为RegeditUser方法的一部门。在阅读源代码时仅仅知道UserController使用了EmailSender。相比之下,EmialSender已经明确依赖了NetworkClient和MessageFactory,并且在构造函数中进行了初始化。同样的,NetworkClient已经明确的依赖了EmailServerSetting类。
依赖注入旨在决绝反转依赖链。以代替UserController去手动的创建依赖,深入代码实现的细节中,已经创建了通过构造函数注入EmailSender创建的实例。
现在,很明显了,需要一些事情去创建对象,所以这些代码对象需要在某处存活。负责创建对象的服务称为 DI 容器或IoC容器。常见的DI容器有:Autofac,StructureMap, Unity, Ninject, Simple Injector . . .
使用DI容器的关系图如下:
此时UserController中的代码如下图所示:
DI容器的优势就说职责单一:创建对象或服务。向容器请求一个服务的实例,并且计算出增氧创建一个依赖图,但这些都依赖于怎样配置它们。
使用明显的依赖的优势就是,在一个方法中你永远不会在写混乱的方法了。DI容器可以检查你的服务的构造方法并且计算出代码自身中重要的部分。DI容器是可以配置的,所以你可以手动创建可提供的服务的实例。它可以通过接口让你的代码保持松耦合。
在面向对象语言中耦合是一个很重要的概念。它指出一个类怎样去依赖其它类并且执行它自己的函数。松耦合的代码不需要知道一个特别组件的很多细节,就直接可以去使用它。
在UserController中初始化EmailSender就说紧耦合的,你需要直接的创建EmialSender的实例。一个难点就是这个代码很难去测试,任何尝试测试UserController的方法将导致发送邮件。将 EmailSender 作为构造函数参数,并删除创建对象的职责将会减少代码的耦合。如果EmialSender的实现变了,让它依赖于另一个实现,不需要在同时更新更新UserController。
通过接口变成在设计模式中是一种常见的方法,它减少了系统中的耦合。并且还不会绑定到单一的实现,并且这也让类变的可以测试。所以可以创建一个IEmialSender接口,让EmailSender实现它:
用户控制器的代码如下:
现在UserController已经不用关心依赖是怎么实现的了,仅仅实现了IEmailSender接口并且暴露了SendEmail方法。现在应用程序的代码已经独立于实现了。现在已经实现了松耦合的代码了。但是又有一个问题:应用程序怎么知道使用EmailSender去代替DummyEmailSender,DI容器告诉你答案:当你需要IEmailSender,使用EmailSender去注册。
怎样在DI容器中注册接口和实现非常依赖DI容器的实现方式,但是基本所有DI容器的原则都是一样的。ASP.NET Core包含开箱即用的简单DI容器,所以让我们看下在一个典型的请求中怎样使用它。
2.在ASP.NET Core中使用依赖注入
本章详细的内容将在下篇博客中详细说明。
原文地址:https://www.cnblogs.com/fengye310/p/11008950.html