我发现我的构造函数开始看起来像这样:
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
不断增加的参数列表。由于“容器”是我的依赖项注入容器,所以为什么我不能这样做:
public MyClass(Container con)
每堂课?不利之处是什么?如果执行此操作,则感觉就像我在使用精美的静态方法。请分享您对IoC和依赖注入疯狂的想法。
我发现我的构造函数开始看起来像这样:
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
不断增加的参数列表。由于“容器”是我的依赖项注入容器,所以为什么我不能这样做:
public MyClass(Container con)
每堂课?不利之处是什么?如果执行此操作,则感觉就像我在使用精美的静态方法。请分享您对IoC和依赖注入疯狂的想法。
Answers:
正确的是,如果将容器用作服务定位器,则它或多或少是光荣的静态工厂。由于种种原因,我认为这是一种反模式。
构造函数注入的奇妙好处之一是,它使违反单一责任原则的行为显而易见。
发生这种情况时,就该重构Facade Services了。简而言之,创建一个新的,更粗粒度的接口,以隐藏您当前需要的一些或所有细粒度依赖项之间的交互。
我认为您的类构造函数不应引用您的IOC容器时间。这表示您的类和容器之间不必要的依赖关系(IOC试图避免的依赖关系类型!)。
MyClass myClass = new MyClass(IDependency1 interface1, IDependency2 interface2)
(接口参数)。这与@derivation的帖子无关,我将其解释为依赖性注入容器不应将自身注入其对象,即MyClass myClass = new MyClass(this)
传递参数的困难不是问题。问题是您的课程做得太多,应该细分得更多。
依赖注入可以作为类过大的预警,特别是因为传递所有依赖的痛苦越来越大。
我遇到了一个类似的问题,关于基于构造函数的依赖注入,以及传递所有依赖的复杂程度。
我过去使用的一种方法是通过服务层使用应用程序外观模式。这将具有粗略的API。如果此服务取决于存储库,它将使用私有属性的setter注入。这需要创建一个抽象工厂,并将创建存储库的逻辑转移到工厂中。
带有说明的详细代码可以在这里找到
我阅读了整个主题两次,并且我认为人们是根据他们所知道的而不是根据所要求的做出回应。
JP最初的问题看起来像是先发送一个解析器,然后再发送一堆类来构造对象,但我们假设这些类/对象本身就是服务,已经可以注入。如果不是,那该怎么办?
JP,如果您希望利用DI 并希望将注入与上下文数据混合在一起的荣耀,那么这些模式(或所谓的“反模式”)都不会专门解决这个问题。实际上可以归结为使用一个可以为您提供支持的软件包。
Container.GetSevice<MyClass>(someObject1, someObject2)
...很少支持这种格式。我相信对这种支持进行编程的困难,加上与实现相关的糟糕性能,使得它对开源开发人员没有吸引力。
但是应该这样做,因为我应该能够为MyClass创建并注册一个工厂,并且该工厂应该能够接收仅仅为了传递而没有被推为“服务”的数据/输入。数据。如果“反模式”是负面影响,那么强制存在用于传递数据/模型的人工服务类型肯定是负面的(与您将类包装到容器中的感觉相同。本能也适用)。
尽管有些框架看起来有些难看,但有些框架可能会有所帮助。例如,Ninject:
那是针对.NET的,很流行,仍然没有应有的清晰,但是我敢肯定,无论您选择使用哪种语言,都有一些东西。
问题:
1)具有不断增加的参数列表的构造函数。
2)如果类是继承的(例如:),RepositoryBase
则更改构造函数签名会导致派生类发生更改。
解决方案1
传递IoC Container
给构造函数
为什么
为什么不
解决方案2
创建一个将所有服务分组的类,并将其传递给构造函数
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;
}
}
派生类
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;
}
}
为什么
A
依赖的类,则该信息将累积在A.Dependency
为什么不
X.Dependency
)IoC Container
解决方案2只是一个原始的方法,如果对此有可靠的论点,那么描述性的评论将不胜感激。
这是我使用的方法
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; }
}
这是一种粗略的方法,如何在注入值之后执行注入并运行构造函数。这是功能齐全的程序。
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);
}
}
我目前正在从事一个爱好项目,其工作原理如下 :https://github.com/Jokine/ToolProject/tree/Core
您使用什么依赖注入框架?您是否尝试过使用基于setter的注入?
基于构造函数的注入的好处是,对于不使用DI框架的Java程序员来说,它看起来很自然。您需要5件事来初始化一个类,然后为构造函数提供5个参数。缺点是您已经注意到,当您有很多依赖项时,它变得笨拙。
使用Spring时,您可以通过setter传递所需的值,并且可以使用@required注释强制注入它们。缺点是您需要将初始化代码从构造函数移至另一个方法,并在将所有依赖项注入后通过@PostConstruct进行标记,从而让Spring调用Spring。我不确定其他框架,但我认为它们会做类似的事情。
两种方式都起作用,这是一个优先事项。