Inversion of Control是让框架回调到用户代码的概念。这是一个非常抽象的概念,它只是描述了一个库和一个框架之间的区别,或者它可以被描述为“一个框架的定义特征”。我们的代码调用了一个库,而一个框架控制着我们的代码。任何框架提供了钩子,允许我们插入我们的代码。
Inversion of Control是一种模式,只有在构建框架时您是框架开发人员,或者您是应用程序开发人员与框架代码交互时才可以应用。但是,IoC在专门处理应用程序代码时不适用。
取决于抽象而不是实现的行为称为依赖性反转,而依赖性反转可以由应用程序和框架开发人员实践。所以你所说的IoC实际上是依赖性倒置,正如Krzysztof所说的那样:你所做的不是IoC。我从现在开始讨论依赖倒置。
基本上有两种依赖倒置的形式/实现:服务定位器和依赖注入。
使用服务定位器模式,您需要依赖关系在类中调用静态工厂。在一般情况下,它看起来像这样:
public class Service
{
public void SomeOperation() {
IDependency dependency =
ServiceLocator.GetInstance<IDependency>();
dependency.Execute();
}
}
这个例子应该熟悉你,因为这你做你的Logon
方法是什么:您正在使用Service Locator模式。
随着依赖注入模式,你注入一个类需要从外部的所有依赖项;最好使用构造函数。类本身不负责获得它的依赖关系。这个责任被调高了。上述类是这样当使用依赖注入:
public class Service
{
private readonly IDependency dependency;
public Service(IDependency dependency)
{ this.dependency =依赖; }
public void SomeOperation()
{ this.dependency.Execute(); }}
两种模式是依赖倒置,因为在这两种情况下,Service
类是不负责创建的依赖关系,不知道它正在使用的实现。它只是与界面进行交谈。这两种模式都为您提供了一个类正在使用的实现的灵活性,从而允许您编写更灵活的软件。
然而,服务定位器模式存在很多问题,这就是为什么它被认为是反模式。您已经遇到了这些问题,因为您想知道依赖反转(您的案例中的服务定位器)如何帮助您进行单元测试。
答案是Service Locator模式对单元测试没有帮助。相反:它使得单元测试非常困难。通过让该类调用ObjectFactory
,可以在两者之间创建一个硬依赖关系。替换IAccountRepository
进行测试,也意味着您的单元测试必须使用ObjectFactory
。这使得你的单元测试更难阅读。但更重要的是,由于ObjectFactory
是一个静态实例,所有的单元测试都使用同一个实例,这使得难以在每个测试的基础上独立运行测试和交换实现。
我过去使用过服务定位符模式,并且我处理这个的方式是通过在我的服务定位器中注册依赖关系,我可以逐线程地改变依赖关系(使用[ThreadStatic]字段封面)。这使我可以并行运行我的测试(默认情况下是MSTest),同时保持测试隔离。然而,这个问题是这个问题变得非常复杂,使用各种技术手段使测试变得困难,这让我花了很多时间解决这些技术问题,而我本可以编写更多的测试。
这些问题的真正解决方案是依赖注入。一旦你通过构造函数注入了一个类需要的依赖关系,所有这些问题就会消失。这不仅明确了类需要什么依赖关系(没有隐藏的依赖关系),而且每个单元测试本身都负责注入它所需的依赖关系。这使得编写测试变得更加容易,并且可以防止您在单元测试中配置DI容器。
延伸阅读:Service Locator is an Anti-Pattern。
这不是IoC。 – 2012-03-25 06:47:35