Questions tagged «dependency-injection»

依赖注入是一种设计模式,其中通过构造函数,方法或字段(属性)设置组件的依赖关系(对象的实例,属性)。它是更一般的依赖项反转的一种特殊形式。

2
依赖注入与静态方法
今天,我与另一位开发人员进行了有趣的讨论,内容涉及如何使用接受字符串并输出字符串的方法处理类。 想象一下以下内容,它完全是出于示例目的而组成的 public string GetStringPart(string input) { //Some input validation which is removed for clarity if(input.Length > 5) return input.Substring(0,1); if(input.Substring(0,1) == "B") return input.Substring(0,3); return string.empty; } 一个基于字符串输入而具有某种逻辑的函数将使用DI添加到项目中,并且具有一个DI容器。您是否会使用接口添加此新类并在需要时将其注入,还是将其设为静态类?各自的优缺点是什么?您为什么要(或不希望)使它与构造函数注入一起使用,而不是在需要时随处访问。

5
在几乎每个人都需要访问公共数据结构的情况下,依赖项注入有什么好处?
在OOP中,为什么全局变量是邪恶的有很多原因。 如果需要共享的对象的数量或大小太大而无法在函数参数中有效传递,通常每个人都建议使用依赖注入而不是全局对象。 但是,在几乎每个人都需要了解某种数据结构的情况下,为什么依赖注入比全局对象更好? 示例(一个简化的示例,以大体上说明这一点,而无需在特定应用程序中深入研究) 许多虚拟车辆具有大量的属性和状态,包括类型,名称,颜色,速度,位置等。许多用户可以对其进行远程控制,并且发生大量事件(用户都可以已启动和自动)可以更改其许多状态或属性。 天真的解决方案是仅将它们制成一个全局容器,例如 vector<Vehicle> vehicles; 可以从任何地方访问。 更加面向OOP的解决方案是让容器成为处理主事件循环的类的成员,并在其构造函数中实例化。每个需要它并且是主线程成员的类都将通过其构造函数中的指针被授予对容器的访问权限。例如,如果外部消息是通过网络连接传入的,则负责解析的类(每个连接一个)将接管,解析器将可以通过指针或引用访问容器。现在,如果解析后的消息导致容器元素发生更改,或者需要容器中的某些数据来执行操作,则无需通过信号和插槽来扔掉成千上万个变量(或更糟的是,将它们存储在解析器中,稍后由调用解析器的人检索)。当然,所有通过依赖注入接收对容器的访问的类都是同一线程的一部分。不同的线程不会直接访问它,但是会执行其工作,然后将信号发送到主线程,并且主线程中的插槽将更新容器。 但是,如果大多数类都可以访问该容器,那么到底它与全局容器有什么不同呢?如果这么多的类需要容器中的数据,那么“依赖注入方式”是否只是伪装的全局变量? 一个答案将是线程安全性:即使我注意不要滥用全局容器,也许将来另一个开发人员在紧迫的最后期限的压力下,仍会在另一个线程中使用全局容器,而不会照顾所有人碰撞情况。但是,即使在依赖注入的情况下,也可能会向在另一个线程中运行的某个人提供指针,从而导致相同的问题。

2
理解“接缝”一词的问题
我正在阅读Mark Seemann撰写的“ .NET中的依赖项注入”(这太棒了,而且必须有),并且作者经常使用“ seam”一词。但我不明白这意味着什么。这是使用此词的示例: 第7章介绍了如何在各种具体框架(例如ASP.NET MVC,WPF,WCF等)中组成对象。并非所有框架都同样出色地支持DI,即使在那些框架中,DI的实现方式也有很大差异。对于每个框架,可能很难确定在该框架中启用DI的SEAM。但是,一旦找到SEAM,您就会为使用该特定框架的所有应用程序找到一个解决方案。在第7章中,我已经为最常见的.NET应用程序框架完成了这项工作。可以将其视为框架SEAMS的目录。 感谢您帮助我理解这个词。

2
贫血域模型和域服务注入
所述贫血域模型被描述为由Martin Fowler在领域驱动设计的反模式。为了在域模型上具有业务逻辑,通常使用域服务。但是Vaughn Vernon认为将域服务注入域模型是有害的(请参阅“实施域驱动设计,第387页”)。 我认为这些意见是矛盾的,这是真的吗?如何兼顾这两点? 是注入域服务与贫血域模型和普通域服务相比真的富域模型吗?

7
抽象是否必须降低代码的可读性?
最近与我合作的一名优秀开发人员告诉我,他在实现我们继承的某些代码中的功能时遇到了一些困难;他说,问题在于该代码难以遵循。由此,我对产品进行了更深入的了解,并意识到查看代码路径有多么困难。 它使用了许多接口和抽象层,以致于很难理解事物的开始和结束位置。这让我开始思考过去的项目的时间(在我很清楚干净的代码原理之前),发现在项目中走来走去非常困难,这主要是因为我的代码导航工具总是使我进入一个界面。找到具体的实现或某些插件类型体系结构中的连接位置将花费大量的额外精力。 我知道有些开发人员正是出于这个原因严格拒绝依赖注入容器。它极大地混淆了软件的路径,以致代码导航的难度成倍增加。 我的问题是:当框架或模式引入如此多的开销时,是否值得?这是模式实施不当的征兆吗? 我想开发人员应该从更大的角度看待抽象带给项目的东西,以帮助他们度过沮丧。通常,尽管如此,很难使他们看到大局。我知道我未能通过TDD出售IOC和DI的需求。对于那些开发人员而言,使用这些工具只会严重限制代码的可读性。


1
编写框架时的依赖注入/ IoC容器实践
我在许多项目中都为.Net使用了各种IoC容器(Castle.Windsor,Autofac,MEF等)。我发现它们往往经常被滥用,并鼓励许多不良行为。 是否有用于IoC容器的既定实践,特别是在提供平台/框架时?作为框架编写者,我的目标是使代码尽可能简单和易于使用。我宁愿写一行代码来构造一个对象,而不是十行甚至两行。 例如,我注意到了一些代码气味,并且对以下内容没有好的建议: 构造函数的大量参数(> 5)。创建服务往往很复杂;尽管所有组件很少是可选的(除了可能在测试中),所有依赖项都是通过构造函数注入的。 缺乏私人和内部阶级;这可能是使用C#和Silverlight的特定限制,但是我对如何解决它感兴趣。如果所有的类都是公共的,很难说框架接口是什么。它使我可以访问我可能不应该接触的私人部件。 将对象生命周期耦合到IoC容器。手动构造创建对象所需的依赖项通常很困难。对象生命周期通常由IoC框架管理。我见过大多数班级都注册为Singletons的项目。您缺乏明确的控制,还被迫管理内部(与上述要点有关,所有类都是公共的,因此您必须注入它们)。 例如,.Net框架具有许多静态方法。例如DateTime.UtcNow。很多次,我都将这种包装和注入作为构造参数。 依赖于具体的实现使我的代码难以测试。注入依赖关系会使我的代码难以使用-特别是在类具有许多参数的情况下。 如何提供可测试的界面以及易于使用的界面?最佳做法是什么?

8
在UnitTesting之外值得依赖注入吗
给定一个构造函数,它永远不必使用初始化它的几个对象的任何不同实现,使用DI仍然可行吗?毕竟,我们可能仍要进行单元测试。 有问题的类在其构造函数中初始化了其他一些类,并且使用的类非常特定。它永远不会使用其他实现。我们有理由避免尝试对接口进行编程吗?

5
何时使用接口(单元测试,IoC?)
我怀疑我在这里犯了一个小学生错误,正在寻求澄清。我的解决方案(C#)中有很多类-敢于说大多数-我最终为之编写了相应的接口。例如,即使我永远不可能用其他实现替换该计算器,也可以使用“ ICalculator”接口和实现该接口的“ Calculator”类。而且,这些类中的大多数与其依赖项都位于同一个项目中-实际上,它们仅需为internal,但最终成为public实现其各自接口的副作用。 我认为这种为所有内容创建接口的做法源于一些谬误: 1)我本来以为创建单元测试模拟必须有一个接口(我使用的是Moq),但是后来我发现,如果类的成员为virtual,则可以模拟该类,并且该类具有无参数的构造函数(如果我错了)。 2)我本来以为必须要有一个接口才能向IoC框架(Castle Windsor)注册一个类,例如 Container.Register(Component.For<ICalculator>().ImplementedBy<Calculator>()... 实际上,我可以针对自身注册具体类型: Container.Register(Component.For<Calculator>().ImplementedBy<Calculator>()... 3)使用接口(例如,用于依赖项注入的构造函数参数)会导致“松散耦合”。 那我对接口发疯了吗?!我知道您通常会“使用”接口(例如公开公共API)或“可插入”功能之类的场景。我的解决方案只有少数适​​合此类用例的类,但我想知道是否所有其他接口都是不必要的,应该删除?关于上述第3点,如果这样做,我是否会违反“松散耦合”? 编辑:-我只是在玩Moq,它似乎要求方法是公共的和虚拟的,并具有公共的无参数构造函数,以便能够模拟它们。这样看来我不能拥有内部类了吗?

2
DDD-Lite是一种用于依赖注入的模式语言吗?
我偶然发现了格雷格·杨(Greg Young)的演讲DDD项目失败的7个原因,他在7:20提到了他称为DDD-Lite的内容。 概括地说,他基本上说有些人将DDD用作模式语言(实体,存储库,值对象,服务等),而没有做任何其他与DDD相关的事情。他假设.Net中60%或更多的域模型是DDD-Lite。他认为DDD-Lite基本上是在围绕依赖注入构建一种语言,而您实际上并不需要这样做。他说要么完全做DDD,要么做一些简单的事情。否则,他声称一个人正在为构建良好的抽象而进行所有这些工作,但是没有任何实际的好处。 我必须承认,我对DDD的了解不尽如人意,并且还没有尝试使用它。我也没有读过Eric Evan的书。我对依赖注入更加感兴趣,关于此主题的许多书籍和博客都使用Eric Evans的DDD书籍中的术语和参考概念。这是我接触过DDD概念的地方。我一直在阅读的书籍包括: .NET中的依赖注入 Microsoft .Net:为企业设计应用程序 .NET中的Brownfield应用程序开发 如果要进行依赖注入,那么比“ DDD-Lite”更简单的选择是什么?在我看来,建立良好的抽象非常有用,无论人们是否以“ DDD-Lite”方式使用DDD中的概念。(请参阅Mark Seemann的博客文章:接口不是抽象,而是迈向更好的抽象)。我很难相信每个进行依赖注入的人也都在做(或需要做)完整的DDD。我是否以某种方式误解了格雷格·扬(Greg Young)关于DDD-Lite的论点?

3
请用IoC容器卖给我
我已经看到一些建议在代码中使用IoC容器的方法。动机很简单。采取以下依赖项注入代码: class UnitUnderTest { std::auto_ptr<Dependency> d_; public: UnitUnderTest( std::auto_ptr<Dependency> d = std::auto_ptr<Dependency>(new ConcreteDependency) ) : d_(d) { } }; TEST(UnitUnderTest, Example) { std::auto_ptr<Dependency> dep(new MockDependency); UnitUnderTest uut(dep); //Test here } 进入: class UnitUnderTest { std::auto_ptr<Dependency> d_; public: UnitUnderTest() { d_.reset(static_cast<Dependency *>(IocContainer::Get("Dependency"))); } }; TEST(UnitUnderTest, Example) { UnitUnderTest uut; //Test here …

5
C ++:类应该拥有还是观察其依赖关系?
说我有一个Foobar使用(取决于)class的类Widget。好的时候,将Widgetwolud声明为中的字段Foobar,或者如果需要多态行为,则可以声明为智能指针,并将其在构造函​​数中初始化: class Foobar { Widget widget; public: Foobar() : widget(blah blah blah) {} // or std::unique_ptr<Widget> widget; public: Foobar() : widget(std::make_unique<Widget>(blah blah blah)) {} (…) }; 而且我们已经准备就绪。不幸的是,今天,Java的孩子们会嘲笑我们一旦看到它,这是理所当然的,因为它的夫妇Foobar和Widget在一起。解决方案看似很简单:应用“依赖注入”以使依赖构造脱离Foobar类。但是,C ++迫使我们考虑依赖关系的所有权。想到三个解决方案: 唯一指针 class Foobar { std::unique_ptr<Widget> widget; public: Foobar(std::unique_ptr<Widget> &&w) : widget(w) {} (…) } Foobar要求将所有权Widget转移给它。这具有以下优点: 对性能的影响可以忽略不计。 它很安全,因为它可以Foobar控制生命周期Widget,因此可以确保Widget它不会突然消失。 它是安全的,Widget不会泄漏,并且在不再需要时会被适当破坏。 但是,这是有代价的: 它对如何使用Widget实例设置了限制,例如,不能使用堆栈分配Widgets,Widget不能共享。 共享指针 class …

4
注入依赖关系应该在ctor中还是在每个方法中完成?
考虑: public class CtorInjectionExample { public CtorInjectionExample(ISomeRepository SomeRepositoryIn, IOtherRepository OtherRepositoryIn) { this._someRepository = SomeRepositoryIn; this._otherRepository = OtherRepositoryIn; } public void SomeMethod() { //use this._someRepository } public void OtherMethod() { //use this._otherRepository } } 反对: public class MethodInjectionExample { public MethodInjectionExample() { } public void SomeMethod(ISomeRepository SomeRepositoryIn) { //use SomeRepositoryIn } …

3
我得到依赖注入,但是有人可以帮助我了解对IoC容器的需求吗?
如果这似乎又是一个重复的问题,我深表歉意,但是每次我找到有关该主题的文章时,它大多只是在谈论DI是什么。因此,我得到了DI,但我试图了解每个人似乎都在使用的IoC容器的需求。IoC容器的目的真的只是为了“自动解决”依赖项的具体实现吗?也许我的类往往没有几个依赖关系,也许这就是为什么我认为没什么大不了的,但是我想确保我正确地理解了容器的效用。 我通常将我的业务逻辑分解为一个可能看起来像这样的类: public class SomeBusinessOperation { private readonly IDataRepository _repository; public SomeBusinessOperation(IDataRespository repository = null) { _repository = repository ?? new ConcreteRepository(); } public SomeType Run(SomeRequestType request) { // do work... var results = _repository.GetThings(request); return results; } } 因此,它仅具有一个依赖性,在某些情况下可能具有第二或第三依赖性,但并非经常如此。因此,任何调用此方法的都可以传递其自己的存储库,也可以允许其使用默认存储库。 就我对IoC容器的当前了解而言,该容器所做的只是解析IDataRepository。但是,如果这就是全部,那么我就没有看到太多的价值,因为当没有依赖项传入时,我的操作类已经定义了一个回退。所以我唯一想到的另一个好处是,如果我有多个操作,例如这个使用相同的后备仓库,我可以在注册表/工厂/容器的一个地方更改该仓库。那太好了,是吗?

5
我可以在不破坏封装的情况下使用依赖注入吗?
这是我的解决方案和项目: 书店 (解决方案) BookStore.Coupler (项目) Bootstrapper.cs BookStore.Domain (项目) CreateBookCommandValidator.cs CompositeValidator.cs IValidate.cs IValidator.cs ICommandHandler.cs BookStore.Infrastructure (项目) CreateBookCommandHandler.cs ValidationCommandHandlerDecorator.cs BookStore.Web (项目) Global.asax BookStore.BatchProcesses (项目) Program.cs Bootstrapper.cs: public static class Bootstrapper.cs { // I'm using SimpleInjector as my DI Container public static void Initialize(Container container) { container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>), typeof(CreateBookCommandHandler).Assembly); container.RegisterDecorator(typeof(ICommandHandler<>), typeof(ValidationCommandHandlerDecorator<>)); container.RegisterManyForOpenGeneric(typeof(IValidate<>), AccessibilityOption.PublicTypesOnly, (serviceType, …

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.