依赖注入 – 依赖注入与Ninject,MVC 3并使用服务定位器模式

从我读到另一个stackoverflow问题的一个答案(确切的说,我现在在这里),一个用户表达了一些类似“如果你打电话给服务定位器,你做错了”的东西.

这是一个声望很高的人(在数十万,我想),所以我倾向于认为这个人可能会知道他们在说什么.自从我第一次开始学习以及与单元测试相关的程度,我一直在为自己的项目使用DI.这是我现在相当舒服的事情,我想我知道我在做什么.

但是,有很多地方我一直在使用服务定位器来解决项目中的依赖关系.一旦我们的ModelBinder实现就出现了.

典型模型粘合剂的例子.

public class FileModelBinder : IModelBinder {
    public object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext) {
        ValueProviderResult value = bindingContext.ValueProvider.GetValue("id");

        IDataContext db = Services.Current.GetService<IDataContext>();
        return db.Files.SingleOrDefault(i => i.Id == id.AttemptedValue);
    }
}

不是一个真正的实现 – 只是一个快速的例子

由于ModelBinder的实现在首次请求Binder时需要一个新的实例,所以不可能在此特定实现的构造函数上使用依赖注入.

在很多课上就是这样.另一个例子是缓存到期过程,当缓存对象在我的网站中到期时运行方法.我运行一堆数据库调用,而不是.我也在使用服务定位器来获取所需的依赖关系.

最近我发现另一个问题(我在这里发布了一个问题)是所有我的控制器都需要一个IDataContext的实例,我使用了DI – 但是一个动作方法需要一个不同的IDataContext实例.幸运的是,Ninject以命名的依赖来救援.然而,这感觉像是一个污泥,而不是一个真正的解决方案.

我以为我至少理解了关注分离的概念,但是我理解依赖注入和服务定位器模式似乎有些根本错了 – 我不知道是什么.

我现在理解的方式 – 这也可能是错误的 – 至少在MVC中,ControllerFactory会为控制器寻找一个构造函数,并调用服务定位器本身获取所需的依赖关系,然后将它们传入.,我可以明白,并不是所有的课程和没有一个工厂来创建它们.所以在我看来,一些服务定位器模式是可以接受的…但…

>什么时候不能接受?
>当我应该重新思考我如何使用服务定位器模式时,应该怎样看待什么样的模式?
>我的ModelBinder实现错误?如果是这样,我需要学习如何解决它?
>在另一个问题沿着这个用户Mark Seemann推荐一个抽象工厂 – 这是如何相关的?

我想是这样 – 我不能真正想到任何其他问题,以帮助我的理解,但任何额外的信息是非常感谢.

我明白DI可能不是一切的答案,我可能会在实现它的过程中失败,但是,它似乎以我期望与单元测试的方式工作,而不是.

我不是在寻找代码来修复我的示例实现 – 我正在寻找学习,寻找一个解释来解决我的有缺陷的理解.

我希望stackoverflow.com有能力保存草稿问题.我也希望任何回答这个问题的人得到适当的声誉来回答这个问题,因为我认为我要求很多.提前致谢.

考虑以下几点:
public class MyClass
{
  IMyInterface _myInterface;
  IMyOtherInterface _myOtherInterface;

  public MyClass(IMyInterface myInterface,IMyOtherInterface myOtherInterface)
  {
    // Foo

    _myInterface = myInterface;
    _myOtherInterface = myOtherInterface;
  }
}

通过这种设计,我可以表达我的类型的依赖关系.该类型本身不负责知道如何实例化任何依赖性,它们通过任何使用的解析机制(通常是IoC容器)而被赋予它(注入).鉴于:

public class MyClass
{
  IMyInterface _myInterface;
  IMyOtherInterface _myOtherInterface;

  public MyClass()
  {
    // Bar

    _myInterface = ServiceLocator.Resolve<IMyInterface>();
    _myOtherInterface = ServiceLocator.Resolve<IMyOtherInterface>();
  }
}

我们的课程现在依赖于创建特定实例,但是通过委派给服务定位器.在这个意义上,服务位置可以被认为是一种反模式,因为您不会暴露依赖关系,但是您可以通过编译来捕获可以通过编译触发运行时的问题. (好阅读是here).你隐藏复杂性

一个或另一个之间的选择真的取决于你的建筑物和它提供的服务.通常,如果您从零开始构建应用程序,我会一直选择DI.它提高了可维护性,促进了模块化,使测试类型变得更加容易.但是,以ASP.NET MVC3为例,您可以轻松地将SL作为烘焙设计实现.

您可以随时使用复合设计,您可以在SL中使用IoC / DI,就像使用Common Services Locator一样.您的组件可以通过DI进行连接,但可以通过SL进行曝光.您甚至可以将组合投入组合中,并使用像Managed Extensibility Framework(本身支持DI,但也可以连接到其他IoC容器或服务定位器)之类的东西.这是一个很大的设计选择,一般来说我的建议可能是IoC / DI.

你的具体设计我不会说是错的.在这种情况下,您的代码不负责创建模型绑定器本身的实例,这取决于框架,因此您无法控制,但是您可能会轻易更改使用服务定位器以访问IoC容器.但是在IoC容器上调用解决方案的行为你不会认为该服务位置?

凭借抽象的工厂模式,工厂专门制作特定类型.您不注册解析类型,您实际上注册一个抽象工厂,并构建您可能需要的任何类型.使用服务定位器,它旨在定位服务并返回这些实例.从常规的角度来看,行为类似,但行为差异很大.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结