控制反转,依赖性反转和服务定位器差异澄清

时间:2013-05-07 04:37:52

标签: dependency-injection inversion-of-control service-locator

我查看了这些概念,我想看看我是否正确理解了它们。主要是,我试图区分这三个概念。从谷歌搜索和其他结果来看,我看到了人们提供的很多关于它们的细节,但其中许多要么对我不完全清楚,要么矛盾,要么交换概念(IoC / DI)。我试图以更简单的方式定义它们,这对我来说更容易消化,我想看看它是否足够准确。

控制倒置

客户端类不直接实例化其依赖字段的实现类,因为它依赖于其他一些外部类/源来提供它们。在大多数情况下,字段是父类或接口,它具有一个或多个子类,将作为实现提供。

依赖注入

客户端类接收其依赖字段的实现类,无论是通过构造函数,setter还是其他,以及此实现 是一个全新的对象实例。供应类可能使用另一种模式,例如工厂,以确定传递给客户端的实现(或者甚至可以直接实例化新实例并将其传递到客户端的构造函数中)。

服务定位器

客户端类是调用服务定位器以提供其依赖字段的类。返回的实现是一个对象实例,可以与依赖于相同依赖关系的任何其他客户端类共享。

我尝试了一个非常简单的例子:

DI:

public interface IX {

}

public class X : IX {

}

public class A {
    IX depField;

    public A(IX depField) {
        this.depField = depField;
    }   
}

public void main() {
    A myClass = new A(new X());
}

SL:

public interface IX {

}

public class X : IX {

}

public class A {
    IX depField = serviceLocatorObj.GetService<IX>(); 
    //where IX is mapped to X in the service locator class
}

public void main() {
    A myClass = new A();
}

IoC是接收方的概念,其中DI和SL是处理供应方概念的两种可能方式。

感谢。如果我错误地使用了任何条款,我也会道歉。

编辑:感谢您的回复!

2 个答案:

答案 0 :(得分:2)

是的,你是对的。

SL通常在框架内部使用,以便能够找到所有服务。从开发人员的角度来看,他们只是使用依赖注入,因为框架隐藏了服务位置。一个典型的例子是ASP.NET MVC,您可以在控制器中使用DI。 ASP.NET通过DependencyResolver类在内部使用服务位置,以允许您使用DI。

对于业务线应用程序,DI优先于SL,因为SL隐藏了依赖关系,这反过来又使得维护应用程序变得更加困难。

答案 1 :(得分:1)

服务地点也使得单元测试更加困难,因为它们通常是静态类,这会破坏模拟它们的能力。

考虑构造函数注入和服务位置的这些示例。

服务地点:

 public class Foo
    {
        public void DoSomething()
        {
            var provider = ServiceLocator.GetInstance<IProvider>();

            provider.DoIt();
        }
    }

构造函数注入:

 public class Foo
    {
        private readonly IProvider _provider;

        public Foo(IProvider provider)
        {
            _provider = provider;
        }

        public void DoSomething()
        {
            _provider.DoIt();
        }
    }

在构造函数中传递模拟/伪造的IProvider很简单,而在服务定位器示例中,当您首先需要抽象ServiceLocator类时,这会变得更加指数。

    [Test]
    public void DoSomething_ShouldCallDoIt()
    {
        var mockProvider = new Mock<IProvider>();

        var foo = new Foo(mockProvider);

        foo.DoSomething();

        mockProvider.Verify(x => x.DoIt());
    }