这两种模式看起来都像是控制反转原理的实现.也就是说,一个对象不应该知道如何构造它的依赖关系.
依赖注入(DI)似乎使用构造函数或setter来"注入"它的依赖项.
使用构造函数注入的示例:
//Foo Needs an IBar
public class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
//...
}
Run Code Online (Sandbox Code Playgroud)
服务定位器似乎使用了一个"容器",它连接了它的依赖关系并给它foo吧.
使用服务定位器的示例:
//Foo Needs an IBar
public class Foo
{
private IBar bar;
public Foo()
{
this.bar = Container.Get<IBar>();
}
//...
}
Run Code Online (Sandbox Code Playgroud)
因为我们的依赖项只是对象本身,所以这些依赖项具有依赖项,它们具有更多依赖项,依此类推.因此,控制容器的反转(或DI容器)诞生了.示例:Castle Windsor,Ninject,Structure Map,Spring等)
但是,IOC/DI容器看起来完全相同像一个服务定位器.将它称为DI容器是一个坏名字?IOC/DI容器只是另一种服务定位器吗?当我们有很多依赖关系时,我们使用DI容器这一事实的细微差别是什么?
最近我读过Mark Seemann关于Service Locator反模式的文章.
作者指出ServiceLocator为反模式的两个主要原因:
API使用问题(我完全可以使用)
当类使用服务定位器时,很难看到它的依赖关系,因为在大多数情况下,类只有一个PARAMETERLESS构造函数.与ServiceLocator相比,DI方法通过构造函数的参数显式地暴露依赖关系,因此在IntelliSense中很容易看到依赖关系.
维护问题(让我感到困惑)
请考虑以下示例
我们有一个使用服务定位器方法的类'MyType':
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们要为类'MyType'添加另一个依赖项
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我的误解开始的地方.作者说:
要判断你是否引入了一个重大改变,要变得更加困难.您需要了解使用Service Locator的整个应用程序,并且编译器不会帮助您.
但是等一下,如果我们使用DI方法,我们将在构造函数中引入与另一个参数的依赖关系(在构造函数注入的情况下).问题仍然存在.如果我们忘记设置ServiceLocator,那么我们可能忘记在IoC容器中添加新的映射,并且DI方法将具有相同的运行时问题.
此外,作者还提到了单元测试的难点.但是,我们不会有DI方法的问题吗?我们不需要更新所有实例化该类的测试吗?我们将更新它们以传递一个新的模拟依赖项,以使我们的测试可编译.我没有看到更新和时间花费带来任何好处.
我不是想捍卫Service Locator方法.但这种误解让我觉得我失去了一些非常重要的东西.有人可以消除我的怀疑吗?
更新(摘要):
我的问题"服务定位器是反模式"的答案实际上取决于具体情况.我绝对不会建议你从工具列表中删除它.当您开始处理遗留代码时,它可能会变得非常方便.如果你很幸运能够处于项目的最初阶段,那么DI方法可能是更好的选择,因为它比Service Locator有一些优势.
以下是主要的不同之处,这些差异使我不相信我的新项目使用Service Locator:
有关详细信息,请阅读下面给出的优秀答案.
design-patterns dependency-injection anti-patterns service-locator
在阅读Mark Seemann的".NET中的依赖注入"后,我远离服务定位器,这是一种反模式.
在阅读MVC 4上的发行说明后,我看到:
通过DependencyResolver改进了控制反转(IoC):Web API现在使用MVC依赖解析器实现的服务定位器模式来获取许多不同设施的实例.
因此,我对于微软在2012年使用服务定位器的原因感到好奇和困惑.
dependency-injection ioc-container service-locator asp.net-mvc-4
乍一看,服务定位器模式与我的抽象工厂模式看起来相同.它们似乎都具有相同的用途(您查询它们以接收抽象服务的实例),并且当我阅读有关依赖注入时它们都被提及.
但是,我已经看到服务定位器模式被描述为一个糟糕的想法,但在至少一个主要的依赖注入框架中看到了对抽象工厂模式的直接支持.
如果它们不相同,有什么区别?
我目前正在权衡DI和SL之间的优缺点.但是,我发现自己处于以下问题22中,这意味着我应该只使用SL作为一切,并且只在每个类中注入一个IoC容器.
DI Catch 22:
一些依赖项,如Log4Net,根本不适合DI.我称之为元依赖关系并认为它们对调用代码应该是不透明的.我的理由是,如果一个简单的类'D'最初是在没有记录的情况下实现的,然后增长到需要记录,那么依赖类'A','B'和'C'现在必须以某种方式获得这种依赖并将其从'A'到'D'(假设'A'组成'B','B'组成'C',依此类推).我们现在已经进行了重要的代码更改,因为我们需要登录一个类.
因此,我们需要一种不透明的机制来获取元依赖性.我想到了两个:Singleton和SL.前者具有已知的局限性,主要是关于刚性范围的能力:最好的是Singleton将使用存储在应用程序范围内的抽象工厂(即在静态变量中).这允许一些灵活性,但并不完美.
更好的解决方案是将IoC容器注入此类,然后使用该类中的SL从容器中解析这些元依赖关系.
因此,捕获22:因为类现在正在注入IoC容器,那么为什么不使用它来解析所有其他依赖项呢?
我非常感谢你的想法:)
c# singleton dependency-injection dependency-management service-locator
我一直在寻找Common Service Locator作为抽象我的IoC容器的方法,但我注意到有些人强烈反对这种类型.
人们建议永远不要使用它吗?一直在使用它?或者有时使用它?如果有时候,那么在什么情况下你会使用它以及你不会使用它的情况.
c# dependency-injection inversion-of-control common-service-locator service-locator
考虑这种情况.我有一些业务逻辑,现在需要写入日志.
interface ILogger
{
void Log(string stuff);
}
interface IDependency
{
string GetInfo();
}
class MyBusinessObject
{
private IDependency _dependency;
public MyBusinessObject(IDependency dependency)
{
_dependency = dependency;
}
public string DoSomething(string input)
{
// Process input
var info = _dependency.GetInfo();
var intermediateResult = PerformInterestingStuff(input, info);
if (intermediateResult== "SomethingWeNeedToLog")
{
// How do I get to the ILogger-interface?
}
var result = PerformSomethingElse(intermediateResult);
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
你会如何获得ILogger界面?我看到两种主要的可能性;
你更喜欢哪种方法,为什么?还是有更好的模式?
更新: 请注意,我不需要记录所有方法调用.我只想记录在我的方法中可能发生或可能不发生的一些(罕见)事件.
在搜索 Flutter 的依赖注入解决方案时,我发现了两个很棒的库:provider
和get_it
.
据我所知provider
,它有更多的样板文件,但它非常适合 Flutter ,一旦注入的值发生变化,就Consumer
可以重建Widget
树的一部分。
get_it
另一方面更直接,更容易使用,并且不依赖于 Flutter,因此可以与任何 Dart 代码一起使用。
它们之间还有什么区别和限制吗?我知道这有点自以为是,但 Flutter 太新了,所以最好公开注册好处、副作用和陷阱。
dependency-injection service-locator flutter flutter-provider
我创建了一个ASP.NET Core MVC/WebApi站点,该站点有一个RabbitMQ订阅者,基于James Still的博客文章Real-World PubSub Messaging with RabbitMQ.
在他的文章中,他使用静态类来启动队列订阅者并为排队事件定义事件处理程序.然后,此静态方法通过静态工厂类实例化事件处理程序类.
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace NST.Web.MessageProcessing
{
public static class MessageListener
{
private static IConnection _connection;
private static IModel _channel;
public static void Start(string hostName, string userName, string password, int port)
{
var factory = new ConnectionFactory
{
HostName = hostName,
Port = port,
UserName = userName,
Password = password,
VirtualHost = "/",
AutomaticRecoveryEnabled = true,
NetworkRecoveryInterval = TimeSpan.FromSeconds(15)
};
_connection = factory.CreateConnection();
_channel = …
Run Code Online (Sandbox Code Playgroud) c# dependency-injection rabbitmq service-locator asp.net-core
我正在为遗留的ASP.NET应用程序设计一些体系结构更改.我为一些模拟ASP.NET MVC的IDependencyResolver的依赖项解析的类做了原型.我不会发布,因为它几乎是相同的界面,但用其他自然语言.
我发现它可能被认为是服务位置,反过来通常(在某些情况下不完全)被谴责支持依赖注入.尽管如此,我找不到任何反对使用ASP.NET MVC的依赖项解析实现的建议.
ASP.NET MVC的IDependencyResolver是否被视为反模式?这是件坏事吗?