8

我不确定是不是只有我一个人,但我感觉 ASP.NET MVC 控制器中使用的构造函数注入会导致不必要的资源消耗。

在创建控制器时,仍然需要创建未用于特定 Web 请求的组件。这就像在我渴了牛奶的时候买了摊位牛奶和果汁,然后我就把果汁扔掉了。

比较控制器的构造函数注入和服务定位器的这些示例,以澄清我的担忧。

构造函数注入,创建了展位deps,但只使用了一个。

public class MyController : Controller
{
    private readonly IDep1 _dep1;
    private readonly IDep2 _dep2;

    public MyController(IDep1 dep1, IDep2 dep2)
    {
        _dep1 = dep1;
        _dep2 = dep2;
    }

    public ActionResult Index()
    {
        _dep1.MakeStuff();
        return View();
    }
    public ActionResult PageTwo()
    {
        _dep2.MakeStuff();
        return View();
    }
}

服务定位器,每个 dep 仅在使用时创建。

public class MyController : Controller
{
    public ActionResult Index()
    {
        var dep1 = ServiceLocator.Resolve<IDep1>();
        dep1.MakeStuff();
        return View();
    }
    public ActionResult PageTwo()
    {
        var dep2 = ServiceLocator.Resolve<IDep2>();
        dep2.MakeStuff();
        return View();
    }
}

请注意,IoC 容器(由于许多原因是有益的)仍然可以用于服务定位器模式。我不希望这是围绕 IoC 和容器框架的讨论,也没有构造函数注入的其他好处(依赖关系的清晰可见性等)。我关心的是构造函数注入模式以及它在 ASP.NET MVC 控制器情况下如何浪费资源。

我想这里的主要问题是: 对于上述场景(ASP.NET MVC 控制器),Service Locator 是更好的解决方案性能吗?

4

2 回答 2

8

如果对象创建是您的瓶颈,那么您要么处于非常好的情况(其他一切都像魅力一样工作,因此 < 1 ms 操作计数),要么处于非常糟糕的情况(您的构造函数正在做一些繁重的工作 - 他们不应该这样做至)。

Mark Seemann 已经在这里介绍了这个主题:http: //blog.ploeh.dk/2011/03/04/Composeobjectgraphswithconfidence/

在许多情况下,这是您必须承受的性能损失,因为无论如何您都需要这些类,但有时您可能会担心过早地承受这种性能损失。然而,我声称在绝大多数情况下,这种担忧是无关紧要的。

并提供了一个可能的解决方案,如果它对你仍然很重要(延期分支)。

于 2013-04-02T10:25:46.217 回答
2

如果你不想构造你不需要的东西/使用传递可以构造你需要的东西的东西。

在我们的控制器工厂中使用服务定位器 + DI,我们可以将一个 dep 工厂传递给控制器​​,并允许控制器决定向工厂询问什么。

这不是我们有工厂模式的原因吗?

因此,要在问题中重构您的示例,您可能想做这样的事情......

public class MyController : Controller
{
    private readonly IDepFactory _factory;

    public MyController(IDepFactory factory)
    {
        _factory= factory;
    }

    public ActionResult Index()
    {
        var dep1 = factory.Get<IDep1>();
        dep1.MakeStuff();
        return View();
    }
    public ActionResult PageTwo()
    {
        var dep2 = factory.Get<IDep2>();
        dep2.MakeStuff();
        return View();
    }
}

这既有效又很好地利用了模式。

从测试的角度来看,您可以模拟传入的 IDepFactory,以便它始终返回一些常量,当查询返回已知结果时,您可以确认控制器中的逻辑行为正确。

从性能的角度来看,我认为差异主要取决于每种情况下依赖堆栈的深度,如果依赖堆栈非常浅,您可能更喜欢不使用工厂并像以前一样传入两个 deps因为收益几乎没有。

于 2016-03-24T11:36:27.500 回答