什么是依赖注入?
什么是依赖注入?
这个问题已经在这里有了答案:
可能是重复的:
我正在学习asp.net mvc 3,其中一个新功能是依赖注入。有人可以告诉我什么是依赖注入吗?它为什么有用?何时使用它?谢谢。
事实上,这里有两个问题。一个是“什么是依赖注入?”,另一个是“MVC 3中新增了哪些对依赖注入的支持?”。
依赖注入是一种编程模式,当类在使用其他类之前不定义新对象时(例如,需要将电子邮件记录在数据库中的某个电子邮件发送类不会创建记录器的新实例),而是请求提供它,而不知道它甚至可能是哪个类(在我们的例子中使用一个接口,例如ILogger)。记录器在这里是一个依赖项,它可以通过多种方式请求/注入,例如作为调用类(例如EmailSender)的构造函数参数请求,或仅将其作为类的“设置”访问器上的属性等。
有一些称为依赖注入库或控制反转容器的库。这些都是库,您可以在其中定义真正应在运行时使用的类以及要使用的其他特定值,并告诉它们为您创建对象(例如创建EmailSender的实例),将所有依赖项递归传递给它们(因此,如果ILogger实际上是需要连接字符串的DBLogger,那么它也会发送它)。例如,Windsor、Ninject、Autofac、Microsoft Unity等。
有关示例代码和更清晰的示例,请参见曾经在ASP.NET MVC团队工作过的一位先生制作的这个不错的免费视频:
ASP.NET MVC始终允许使用工厂类,您可以在其中覆盖如何创建控制器类(以便可以使用DI容器库创建控制器及其依赖项,就像它是或EmailSender类一样)。 ASP.NET MVC 3.0中提供了对现有功能的改进,并提供了更多类似方法,以便更容易地在整个ASP.NET MVC中进行DI。
- 官方ASP.NET MVC 3.0发布说明:更多依赖注入支持
- http://blogs.microsoft.co.il/blogs/gilf/archive/2010/10/17/dependency-injection-in-mvc-3-was-made-easier.aspx
- http://johan.driessen.se/archive/2010/10/30/dependency-injection-in-asp.net-mvc-3-got-a-lot-simpler.aspx
以及
- ASP.NET MVC 3服务定位:介绍(第1部分)
- ASP.NET MVC 3服务定位:控制器(第2部分)
- ASP.NET MVC 3服务定位:视图(第3部分)
- ASP.NET MVC 3服务定位:过滤器(第4部分)
深入了解请查看这些内容...
依赖注入是一种将依赖关系提供给消费代码的过程,而不是由该代码负责实例化对象。在一个原始的例子中,你可能有一个类负责计算提供服务的发票。你实例化它并调用它的“Calculate”方法:
public class InvoiceBiller { public void Bill() { Calculator calculator = new Calculator(); var totalAmountDue = calculator.CalculateBill(hoursWorked); } }
这个方法依赖于Calculator类。这很好,它可以工作。不过,依赖注入会让你“注入”Calculator依赖项:
public class InvoiceBiller { private readonly Calculator calculator; public InvoiceBiller(Calculator calculator) { this.calculator = calculator; } public void Bill() { var totalAmountDue = calculator.CalculateBill(hoursWorked); } }
如您所见,第二个示例中InvoiceBiller类通过其构造函数获得了一个Calculator对象(一种称为构造函数注入的依赖注入形式)。InvoiceBiller不再关心如何获得计费器的实例,它只是被赋予了一个实例。
这对于测试很有帮助。你可以通过测试传递任何你想要的Calculator实例。在运行时中的实际产品中,你可以传递一个连接到数据库并查找每小时费率的计算器。为测试,你可以传递使用硬编码费率的计算器,这样你的测试就不需要访问数据库。
更进一步,你通常传递一个接口而不是一个具体类型:
public class InvoiceBiller { private readonly ICalculator calculator; public InvoiceBiller(ICalculator calculator)
现在你正在针对接口而不是实现进行编程。同样,你可以使用模拟框架来创建你的接口类型的模拟,并将其传递给类。