How to avoid Dependency Injection constructor madness?
我发现我的构造函数开始如下所示:
1 | public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... ) |
参数列表不断增加。既然"容器"是我的依赖注入容器,为什么我不能这样做:
1 | public MyClass(Container con) |
每节课?缺点是什么?如果我这样做,感觉就像我在使用一个美化的静电。请分享你对IOC和依赖注射疯狂的看法。
你是对的,如果你使用容器作为服务定位器,它或多或少是一个美化的静态工厂。出于很多原因,我认为这是一种反模式。
构造函数注入的一个好处是它明显地违反了单一责任原则。
当这种情况发生时,是时候重构外观服务了。简而言之,创建一个新的、更粗粒度的接口,它隐藏了您当前需要的一些或所有细粒度依赖项之间的交互。
我认为您的类构造函数不应该参考您的IOC容器周期。这表示类和容器之间不必要的依赖关系(IOC试图避免的依赖类型!).
传递参数的困难不是问题。问题是你的课做得太多了,应该多分解。
依赖注入可以作为类变得太大的早期警告,特别是因为传递所有依赖项的痛苦越来越大。
我遇到了一个类似的问题,关于基于构造函数的依赖项注入,以及传递所有依赖项的过程有多复杂。
我过去使用的方法之一是使用服务层使用应用程序外观模式。这将有一个粗糙的API。如果这个服务依赖于存储库,它将使用私有属性的setter注入。这需要创建一个抽象工厂,并将创建存储库的逻辑移动到工厂中。
详细的代码和解释可以在这里找到
复杂服务层IOC的最佳实践
注入容器是一个你最终会后悔的捷径。
过度注入不是问题,它通常是其他结构缺陷的症状,最显著的是关注点分离。这不是一个问题,但可能有很多来源,所以很难解决这个问题,因为你将不得不处理所有这些问题,有时是同时处理(想想如何清理意大利面)。
这是一份不完整的需要注意的事项清单
糟糕的域设计(聚合根…。等)
关注点(服务组合、命令、查询)分离不良。请参阅CQR和事件源。
或者制图员(小心,这些事情会给你带来麻烦)
查看模型和其他DTO(不要重复使用模型和DTO,并尽量将其保持在最低限度!!!!!)
读这整个线,两次的事情,和我认为是村里的人,他们知道什么反应,不由冰问道。 </P >
JP摩根(JP的原始问题看起来像他建构的对象发送一村的解析器,才一类的一部,但我们的assuming这类/对象是那些本身的服务,成熟的注射。如果他们是怎样诠释? </P >
JP摩根(JP),如果你要找的人到杠杆迪和欲望的荣耀(混合注射用contextual无数据,这些模式(或应该"反型"的),具体来说,是匹配的。它实际上煮下至使用包,这将支持你在这样的努力。 </P >
1 | Container.GetSevice<MyClass>(someObject1, someObject2) |
…………………这冰上极少的格式。在大学的编程难度相信这样的支持,添加到"可怜的绩效,会伴随着丈夫的计算机实施的方法,unattractive开源开发人员。 </P >
但它应该做的,因为在应该能够创建和记录到A厂为MyClass的ES,这厂应该能对接收到的数据输入/那是T pushed到作为一个"服务"正是通过"数据"的缘故。如果"抗冰结构"是消极的后果,然后forcing人工服务的存在(类型为低功率数据/模型冰当然负(在与你的感觉对你的DPS是麻为A类的容器。applies)一样的本能。 </P >
这可能是有帮助的框架,但是,甚至如果他们看A片丑女。例如,ninject: </P >
使用ninject [[Creating审和额外的参数的构造函数 </P >
是的,那是因为.net流行,冰和冰不动,没有为它应该是干净的,但我肯定有什么东西在什么语言的选择对你employ。 </P >
问题: </P >
1)构造函数参数与以往的增长战略。 </P >
2)如果冰继承类(如:
解决方案1 </P >
护照
为什么 </P >
- 没有更多的参数有史以来不断增长的战略
- 构造函数的签名变得简单
为什么不 </P >
- 你的丈夫级紧耦合到IOC容器。(这是当1问题的原因。你想使用这类在其他项目在你使用不同的IOC容器。2。你decide to change IOC容器)
- 你讨厌丈夫的类的描述。(你不能真的看一级建造师说什么和信息需求的功能。)
- 类可以访问潜在的所有服务。
解决方案2 </P >
create a级的这组的所有服务和护照信息到构造函数 </P >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public abstract class EFRepositoryBase { public class Dependency { public DbContext DbContext { get; } public IAuditFactory AuditFactory { get; } public Dependency( DbContext dbContext, IAuditFactory auditFactory) { DbContext = dbContext; AuditFactory = auditFactory; } } protected readonly DbContext DbContext; protected readonly IJobariaAuditFactory auditFactory; protected EFRepositoryBase(Dependency dependency) { DbContext = dependency.DbContext; auditFactory= dependency.JobariaAuditFactory; } } |
源级 </P >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class ApplicationEfRepository : EFRepositoryBase { public new class Dependency : EFRepositoryBase.Dependency { public IConcreteDependency ConcreteDependency { get; } public Dependency( DbContext dbContext, IAuditFactory auditFactory, IConcreteDependency concreteDependency) { DbContext = dbContext; AuditFactory = auditFactory; ConcreteDependency = concreteDependency; } } IConcreteDependency _concreteDependency; public ApplicationEfRepository( Dependency dependency) : base(dependency) { _concreteDependency = dependency.ConcreteDependency; } } |
为什么 </P >
- 新的增级的依赖是不影响衍生类
- 一流大学的冰agnostic IOC容器
- 冰级描述(纵横其dependencies)。村民会议,如果你想知道什么是一流的
A depends在线信息的累积,这是在A.Dependency 冰 - 教官签名变得简单
为什么不 </P >
- 要创建额外的类
- 服务注册成为络合物(你要记录每一个
X.Dependency 分别) - 通过
IoC Container conceptually一样的混蛋 - ………………
溶液2(虽然只是生,如果没有坚实的论据反对它的冰,然后会appreciated描述性的评论 </P >
这是使用的方法 </P >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class Hero { [Inject] private IInventory Inventory { get; set; } [Inject] private IArmour Armour { get; set; } [Inject] protected IWeapon Weapon { get; set; } [Inject] private IAction Jump { get; set; } [Inject] private IInstanceProvider InstanceProvider { get; set; } } |
这里是一个粗的方法对perform的技术和售后injections馏构造函数注入的价值观。这是全功能的程序。 </P >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | public class InjectAttribute : Attribute { } public class TestClass { [Inject] private SomeDependency sd { get; set; } public TestClass() { Console.WriteLine("ctor"); Console.WriteLine(sd); } } public class SomeDependency { } class Program { static void Main(string[] args) { object tc = FormatterServices.GetUninitializedObject(typeof(TestClass)); // Get all properties with inject tag List<PropertyInfo> pi = typeof(TestClass) .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) .Where(info => info.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0).ToList(); // We now happen to know there's only one dependency so we take a shortcut just for the sake of this example and just set value to it without inspecting it pi[0].SetValue(tc, new SomeDependency(), null); // Find the right constructor and Invoke it. ConstructorInfo ci = typeof(TestClass).GetConstructors()[0]; ci.Invoke(tc, null); } } |
我工作在一个currently爱好这厂这样的项目 http:/ / / / toolproject github.com jokine /树/核 </P >
您正在使用什么依赖注入框架?您是否尝试使用基于setter的注入?
基于构造函数的注入的好处是,对于不使用DI框架的Java程序员来说,它看起来是自然的。初始化一个类需要5件事,然后为构造函数提供5个参数。缺点是你已经注意到了,当你有很多依赖性的时候,它会变得笨拙。
使用Spring,您可以使用setter传递所需的值,并且可以使用@required annotations强制注入这些值。缺点是,您需要将初始化代码从构造函数移动到另一个方法,并使用@postconstruct标记在注入所有依赖项之后进行Spring调用。我不确定其他框架,但我认为它们做了类似的事情。
两种方法都有效,这是一个偏好问题。