Bui*_*ted 13 dependency-injection ninject service-locator abstract-factory asp.net-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);
}
}
Run Code Online (Sandbox Code Playgroud)
不是一个真正的实现 - 只是一个简单的例子
由于ModelBinder实现在首次请求Binder时需要新实例,因此无法在构造函数上使用依赖注入来实现此特定实现.
在我的很多课程中都是这样的.另一个例子是Cache Expiration进程,它在我的网站中缓存对象到期时运行一个方法.我运行了一堆数据库调用,什么不是.我也使用服务定位器来获得所需的依赖项.
我最近遇到的另一个问题(我在这里发布了一个问题)是我的所有控制器都需要一个IDataContext实例,我使用了DI - 但是一个动作方法需要一个不同的IDataContext实例.幸运的是,Ninject通过命名的依赖来救援.然而,这感觉像一个kludge而不是一个真正的解决方案.
我认为我至少理解了分离关注的概念,但是我理解依赖注入和服务定位器模式似乎存在根本性的错误 - 我不知道那是什么.
我目前理解它的方式 - 这也可能是错误的 - 至少在MVC中,ControllerFactory为Controller查找构造函数并调用服务定位器本身以获取所需的依赖关系,然后将它们传入.但是,我可以理解,不是所有的类和没有工厂创建它们.所以在我看来,一些服务定位器模式是可以接受的......但......
我想就是这样 - 我无法想到任何其他问题来帮助我理解,但非常感谢任何额外的信息.
我知道DI可能不是解决所有问题的方法,但我可能会在实现它的过程中过分关注,但是,它似乎按照我期望的方式进行单元测试,而不是.
我不是在寻找代码来修复我的示例实现 - 我正在寻找学习,寻找解释以修复我的错误理解.
我希望stackoverflow.com能够保存草稿问题.我也希望无论谁回答这个问题都能获得适当的声誉来回答这个问题,因为我觉得我要求很多.提前致谢.
Mat*_*ott 14
考虑以下:
public class MyClass
{
IMyInterface _myInterface;
IMyOtherInterface _myOtherInterface;
public MyClass(IMyInterface myInterface, IMyOtherInterface myOtherInterface)
{
// Foo
_myInterface = myInterface;
_myOtherInterface = myOtherInterface;
}
}
Run Code Online (Sandbox Code Playgroud)
通过这种设计,我能够表达我的类型的依赖性要求.类型本身不负责知道如何实例化任何依赖关系,它们通过使用的任何解析机制(通常是IoC容器)给予它(注入).鉴于:
public class MyClass
{
IMyInterface _myInterface;
IMyOtherInterface _myOtherInterface;
public MyClass()
{
// Bar
_myInterface = ServiceLocator.Resolve<IMyInterface>();
_myOtherInterface = ServiceLocator.Resolve<IMyOtherInterface>();
}
}
Run Code Online (Sandbox Code Playgroud)
我们的类现在依赖于创建specfic实例,但是通过委托到服务定位器.从这个意义上讲,服务位置可以被认为是一种反模式,因为你没有暴露依赖关系,但是你允许通过编译捕获的问题冒泡进入运行时.(这里读得很好).你隐藏了复杂性.
在一个或另一个之间的选择实际上取决于您的建筑物及其提供的服务.通常,如果您从头开始构建应用程序,我会一直选择DI.它提高了可维护性,促进了模块化,使测试类型变得更加容易.但是,以ASP.NET MVC3为例,您可以轻松地将SL实现为设计.
您可以随时使用IoC/DI和SL的复合设计,就像使用公共服务定位器一样.您可以通过DI连接组件,但通过SL公开.您甚至可以将组合投入混合并使用Managed Extensibility Framework(它本身支持DI,但也可以连接到其他IoC容器或服务定位器).这是一个很大的设计选择,通常我建议尽可能使用IoC/DI.
你的具体设计我不会说是错的.在这种情况下,您的代码不负责创建模型绑定器本身的实例,这取决于框架,因此您无法控制,但您可以轻松更改对服务定位器的使用以访问IoC容器. 但是在IoC容器上调用resolve的操作......你不会考虑该服务位置吗?
通过抽象工厂模式,工厂专门创建特定类型.您没有注册解析类型,实际上您注册了一个抽象工厂,并构建了您可能需要的任何类型.使用服务定位器,它可以定位服务并返回这些实例.类似于会议的观点,但行为却截然不同.