依赖注入或服务位置?

时间:2013-02-06 19:13:48

标签: c# language-agnostic loose-coupling service-locator

我正在努力学习依赖注入,并且还有很多细微之处,我还没有掌握。我为此目的开始阅读的其中一本书是Karl Seguin的Foundations of Programming。有一个关于依赖注入的例子:

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);
        }
    } 
}

然后他继续建议添加另一个间接级别,而不是直接在方法中调用ObjectFactory

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

但实际上这不是“服务地点”吗?

3 个答案:

答案 0 :(得分:2)

是服务定位器。有几种方法可以使用依赖:

  • 聚合(示例案例)

  • 组合物

    • 构造函数中的DI,强制性的(可以在上层使用SL注入)

    • DI属性,可选(可以在上层使用SL注入)

选择什么取决于许多因素,例如它是否是稳定的或不稳定的依赖性,是否需要在测试中模拟它等。有一本关于DI的好书叫做Mark Seemann的“.NET中的依赖注入”

答案 1 :(得分:1)

是的,看起来像我的SL。依赖注入传统上遵循两种模式之一;属性注入或构造注入。

首先,依赖注入比服务位置更省力,但服务位置(SL)有许多负面因素。服务定位器太过简单,只是随心所欲地疯狂地请求服务。这很好,直到你去重构并意识到耦合“太高了”。

使用DI我更喜欢构造函数注入形式,因为它迫使我先想到谁需要什么。

总而言之,我当前的项目是作为一个使用服务定位器的绿色领域项目启动的,因为它给了我“不”考虑依赖关系并让应用程序形状发展的灵活性。后来我一直在重构使用DI,主要是为了处理依赖于什么和原因的东西。

答案 2 :(得分:1)

您的示例是ServiceLocator。某处总有一个ServiceLocator。我想说关键是要理解为什么要直接使用它,以及为什么理想情况下你可能不必使用它。

关键概念是依赖倒置主体。控制框架的依赖注入和反转是促进主体应用的工具。理想情况下,您希望对象构造函数参数是接口定义,将在对象创建时解析。

如果您使用的是现代工具,例如asp.net MVC,那么您可以访问所谓的组合根,它是应用程序的入口点。在MVC中它是控制器。由于您可以访问组合根,因此不需要使用ServiceLocator,因为您可以通过IOC框架从顶部驱动注入,您将注册并设置它。基本上,您的控制器具有构造函数参数,如ISomeService,它在IOC中注册并在创建控制器实例时自动注入。如果ISomeService有一些依赖关系,它们也会在构造函数中作为ISomeUtility,等等,随着对象越来越深入。这是理想的,您永远不需要使用ServiceLocator来解析对象。

如果您处于使用不授予您访问权限的技术的情况,或者您希望在没有IOC框架的应用程序中开始使用IOC框架并且您是第一次添加它那么你可能会发现你无法进入组合根。它可能是框架的限制或代码的质量。在这些情况下,您必须使用ServiceLocator或直接自己创建对象。在这些情况下,使用ServiceLocator是正常的,并且比自己创建该对象更好。