【问题标题】:Dependency injection or service location?依赖注入还是服务定位?
【发布时间】:2013-02-06 19:13:47
【问题描述】:

我正在尝试学习依赖注入,但我还没有掌握其中的许多微妙之处。为此,我开始阅读的其中一本书是 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>();
        }
    }
}

但这不是“服务位置”吗?

【问题讨论】:

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


    【解决方案1】:

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

    • 聚合(示例)

    • 作曲

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

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

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

    【讨论】:

    • 我有 Seemann 的书,但它太详细而且太理论化了(至少我是这么觉得的)。尽管在了解有关该主题的更多信息后,我稍后参考了本书的某些部分,这很有帮助。您还有其他书籍和/或在线资源建议吗?
    • 你可以试试 Bob 叔叔的“敏捷软件开发、原则、模式和实践”。有几章是关于 DI 的。 (无论如何我建议阅读整本书。)
    【解决方案2】:

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

    依赖注入一开始感觉比服务位置更努力,但服务位置 (SL) 有许多负面影响。使用服务定位器太容易了,不能随心所欲地疯狂请求服务,到处都是。这很好,直到你去重构并意识到耦合“太高了”。

    对于 DI,我更喜欢构造函数注入形式,因为它迫使我预先考虑谁需要什么。

    总而言之,我目前的项目是作为一个使用服务定位器的绿地项目开始的,因为它让我能够灵活地“不”考虑依赖关系并让应用程序形态发展。最近我一直在重构以使用 DI,主要是为了了解什么依赖于什么以及为什么。

    【讨论】:

      【解决方案3】:

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

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

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

      如果您使用的技术不允许您访问根目录,或者如果您想在没有 IOC 框架的应用程序中开始使用 IOC 框架并且您是第一次添加它那么你可能会发现你无法进入作文根目录。这可能是框架或代码质量的限制。在这些情况下,您必须使用 ServiceLocator 或自己直接创建对象。在这些情况下,使用 ServiceLocator 是可以的,而且比自己创建该对象要好。

      【讨论】:

      • 这个例子来自书本身,而不是我。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-21
      • 2013-06-28
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多