简体   繁体   English

依赖注入或服务位置?

[英]Dependency injection or service location?

I'm trying to learn dependency injection, and there are many subtleties to it I'm yet to grasp. 我正在尝试学习依赖注入,并且还有很多微妙之处我尚待掌握。 One of the books that I've started reading for that purpose is " Foundations of Programming " by Karl Seguin. 我为此而开始阅读的一本书是Karl Seguin的编程基础 There's an example about dependency injection: 有一个关于依赖注入的示例:

public class Car
{
    private int _id;

    public void Save()
    {
        if (!IsValid())
        {
            //todo: come up with a better exception
            throw new InvalidOperationException("The car must be in a valid state");
        }

        IDataAccess dataAccess = ObjectFactory.GetInstance<IDataAccess>();
        if (_id == 0)
        {
            _id = dataAccess.Save(this);
        }
        else
        {
            dataAccess.Update(this);
        }
    } 
}

And then he goes ahead and suggest adding another level of indirection, rather than calling ObjectFactory directly in the method: 然后他继续建议添加一个间接级别,而不是直接在方法中调用ObjectFactory

public static class DataFactory
{
    public static IDataAccess CreateInstance
    {
        get
        {
            return ObjectFactory.GetInstance<IDataAccess>();
        }
    }
}

But isn't this "Service Location" in fact? 但是,实际上这不是“服务位置”吗?

It is service locator. 它是服务定位器。 There are several of ways to use dependency: 有几种使用依赖项的方法:

  • aggregation (example case) 汇总(示例案例)

  • composition 组成

    • DI in constructor, mandatory (could be injected using SL on upper level) 构造函数中的DI,强制性的(可以使用上层的SL注入)

    • DI in property, optional (could be injected using SL on upper level) 属性中的DI,可选(可以使用较高级别的SL注入)

What to choose depends on many factors, for example whether it is stable or unstable dependency, whether you need to mock it in tests or not etc. There is good book on DI called 'Dependency Injection in .NET' by Mark Seemann. 选择什么取决于许多因素,例如,稳定或不稳定的依赖关系,是否需要在测试中模拟它等等。MarkSeemann撰写了一本关于DI的好书,名为《 .NET中的依赖关系注入》。

Yes, looks like SL to me. 是的,在我看来像SL。 Dependency injection traditionally follows one of two patterns; 传统上,依赖注入遵循以下两种模式之一: property injection or constructor injection. 属性注入或构造函数注入。

Dependency injection feels more effort than service location at first, but service location (SL) has a number of negatives. 首先,依赖注入比服务位置更费力,但是服务位置(SL)具有许多负面影响。 It is far too easy with a service locator to just go crazy requesting services on a whim, all over the place. 使用服务定位器实在太容易了,以至于到处疯狂地请求服务。 This is fine until you go to refactor and realise the coupling is "too damn high". 这很好,直到您进行重构并意识到耦合“太该死的太高”为止。

With DI I prefer the constructor injection form because it forces me to think up front about who needs what. 使用DI时,我更喜欢构造函数注入形式,因为它迫使我预先考虑谁需要什么。

That all said, my current project was started as a green field project using a service locator because it gave me the flexibility "not" to think about dependencies and to let the application shape evolve. 综上所述,我当前的项目是使用服务定位器作为一个绿色项目启动的,因为它给了我“不”考虑依赖关系并让应用程序发展的灵活性。 Latterly I've been refactoring to use DI, mainly to get a handle on what relies on what and why. 最近,我一直在重构使用DI,主要是为了了解什么依赖于什么以及为什么依赖。

Your example is ServiceLocator. 您的示例是ServiceLocator。 There is always a ServiceLocator somewhere. 总有一个ServiceLocator。 I would say the key is to understanding why you would use it directly and why ideally you might not have to. 我要说的关键是要了解为什么您将直接使用它,以及为什么理想情况下不必使用它。

The key concept is the dependency inversion principal. 关键概念是依赖性反转主体。 Dependency injection and inversion of control frameworks are tools that facilitate application of the principal. 依赖注入和控制框架的反转是促进主体应用的工具。 Ideally you want your objects constructor parameters to be interface definitions which will be resolved at object creation time. 理想情况下,您希望对象的构造函数参数为接口定义,这些定义将在对象创建时解析。

If you are using modern tools, such as asp.net MVC then you have access to what is called the composition root which is the entry point of the application. 如果您使用的是诸如asp.net MVC之类的现代工具,那么您就可以访问所谓的合成根,它是应用程序的入口点。 In MVC it's controller. 在MVC中,它是控制器。 Since you have access to the composition root you don't need to use ServiceLocator because injection is driven from the top for you by your IOC framework which you would have registered and setup. 由于您可以访问合成根目录,因此无需使用ServiceLocator,因为注入是由您已经注册和设置的IOC框架从顶部驱动的。 Basically your controller has constructors parameters like ISomeService which is registered with IOC and injected automatically when the controller instance is created. 基本上,控制器具有构造函数参数,例如ISomeService,该参数已在IOC中注册,并在创建控制器实例时自动注入。 If the ISomeService had some dependencies they would also be in the constructor as ISomeUtility, and so forth as your objects get deeper and deeper. 如果ISomeService具有某些依赖关系,则它们也将以ISomeUtility的形式出现在构造函数中,依此类推,随着对象越来越深。 This is ideal and you would never have need to use the ServiceLocator to resolve an object. 这是理想的选择,您将不需要使用ServiceLocator来解析对象。

If you were in a situation using technology that doesn't grant you access to the root or if you were wanting to start using an IOC framework in an application that didn't have one and you were adding it for the first time then you may find you can't get to the composition root. 如果您遇到的情况是使用的技术无法授予您对根的访问权限,或者您想开始在没有该应用程序的应用程序中使用IOC框架,而您是第一次添加它,则可以发现您无法到达合成词根。 It could be a limitation of the framework or the quality of the code. 这可能是框架或代码质量的限制。 In these cases you have to use the ServiceLocator or directly create the object yourself. 在这些情况下,您必须使用ServiceLocator或直接自己创建对象。 In these cases using the ServiceLocator is OK and is better than creating that object yourself. 在这些情况下,使用ServiceLocator是可以的,并且比自己创建该对象更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM