2013-01-04 98 views
3

给出这个MVC控制器的例子;伪代码...MVC DI/IoC太多依赖?

PostController 
{ 
    private IGetPost _getPost; 
    private ICreatePost _createPost; 
    private IDeletePost _deletePost; 
    private IUpdatePost _updatePost; 

    public ActionResult Get() 
    { 
     return _getPost(); 
    } 

    public ActionResult Create(post) 
    { 
     return _createPost(post); 
    } 

    public ActionResult Update(posts) 
    { 
     return _updatePost(post); 
    } 

    public ActionResult Delete(post) 
    { 
     return _deletePost(post); 
    } 
} 

我的问题是,如果控制器上的任一操作被调用时,控制器的所有依赖对他们创建的实例,这似乎是一个性能buzzkill。有一个更好的方法吗?我唯一的想法是创建4个不同的控制器,每个控制器只有一个动作,但这似乎是矫枉过正。我也想过在每个动作中直接调用DependencyResolver,但是我不确定如果我这样做会对单元可测试性产生什么影响。

+0

如果创建IGetPost,ICreatePost ...对象很难,您是否考虑过创建ObjectPool? –

+0

理想情况下,您应该首先避免过多的依赖关系! – frictionlesspulley

回答

1

为什么它是一个性能buzzkill?你有没有这样测量这是怎么回事?虽然在确定的开销采用哪些实现地图到什么接口,最dependency injection(DI)容器称职将做到这一点映射一次(通常动态创建编译的代码,以便查找是尽可能快)来创建映射。

它当时只是一个创建的对象,不会比如果你要使用new keyword不同的事情。

对于一般情况下,这不会是一个性能命中。考虑到这是一个Web应用程序,如果你获得堆栈溢出级别的流量,那么它很好,可能是是缩放的障碍;这些操作中的每一个操作都很便宜,但是当乘以几百万的因素时,总体来说它非常昂贵,并且通常这些是可能导致资源竞争的事物的类型等。

假设这是不是你很好可以面临性能问题的情况下(流量的堆栈溢出水平),是实现构造函数的

如果这四个接口(或其中的任意数量)的实现代价很高,那不是DI的功能,它是代码的函数,这将使您从优化中获益更多。

其中调整依赖注入可能是有益的将是唯一的地方,如果建设一个或一个以上这些实现了高开销,你有你的DI容器创建一个实例所有接口实现,而不是一个实例接口实现。然而,你应该只有当你确定该选项对你是可用的时候,通过DI层查看生命周期管理(意思是说,让这个类的一个实例服务所有请求是可行的;它是线程安全的吗?持有的任何资源,很长一段时间?等等)

如果你真的关心这个和上面的不适或者是不是一种选择,那么,你可以创建一些较小的控制器,这可能是有其他原因的意义;如果您正在执行的操作在逻辑上彼此不相关,则它们可能应该是,并且它们应该位于单独的控制器中。

然而,看着你的行动,似乎你有合乎逻辑的划分是正确的。长期以来,不要试图在没有衡量它的地方对性能进行优化。

也就是说,无论你做什么,做而不是解决你的类内的依赖关系。如果你这样做,你就失去了DI的所有好处,并且将你的课程与DI容器紧密结合在一起(并且可能会在测试过程中杀死它)。

+0

这是一个很好的回应,谢谢。我没有把它评估为任何类型的性能问题,所以我认为你说我担心某些事情是为了担心它,而没有量化的信息来支持它。我使用Ninject,所以我知道我很好。另外,每个服务都非常轻量级(SOLID),所以我不担心任何一个类的实例太重。 –

+0

@DavidHoffman哦,我*爱* Ninject。是的,如果它们很轻,那么,除非你实例化了这些对象的*吨*(这可能在Web应用程序中),那么注入代码*可能会引入开销。我会更新我的答案以反映这一点,但只有当您拥有巨大(如SO尺寸流量)负载时才会出现*极端*边缘情况。 – casperOne

+0

@DavidHoffman更新了这种情况,请参阅第三段。 – casperOne

0

我不确定性能会真的成为一个问题,除非你有一个非常荒谬的数量的依赖关系。无论哪种方式,看看你的架构是一个很好的练习。

我们这样做的方式是将服务级别调用抽象为外部类,称为处理程序。这是从Project Silk的灵感。这样,您不仅可以减少控制器并使其更易于管理,而且可以避免这种依赖性的增加。

在这种情况下,您将拥有一个控制器,对于每个操作,它只是简单地解析处理程序及其依赖项并执行它。处理程序被定义为很少(一种是常见的)方法的小类。

class MyController : BaseController 
{ 
    public ActionResult Get(int id) 
    { 
     return Using<GetItemHandler>().Execute(id); 
    } 
} 

class GetItemHandler 
{ 
    private IDependency _myDep; 

    public GetItemHandler(IDependency dep) 
    { 
     _myDep = dep; 
    } 

    public Execute(int id) 
    { 
     return _myDep.Get(id); 
    } 
} 

注意这个工作的方式是,Using<T>()方法(在BaseController定义)使用IoC容器来解决处理,从而抓住它的所有的依赖。然后,我们可以正常使用它。我认为这种模式确实有助于将职责分开,并保证您的班级和管理员的工作变得精益求精。

+0

这是一个有趣的方法,我将不得不进一步研究它。 –