如何避免依赖注入构造函数的疯狂?

JP *_*son 288 c# java dependency-injection ioc-container inversion-of-control

我发现我的构造函数开始看起来像这样:

public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
Run Code Online (Sandbox Code Playgroud)

随着参数列表不断增加.由于"容器"是我的依赖注入容器,为什么我不能这样做:

public MyClass(Container con)
Run Code Online (Sandbox Code Playgroud)

每个班级?有什么缺点?如果我这样做,感觉我正在使用一个美化的静电.请分享您对IoC和依赖注入疯狂的看法.

Mar*_*ann 394

您是对的,如果您将容器用作服务定位器,它或多或少是一个美化的静态工厂.由于很多原因,我认为这是一种反模式.

构造函数注入的一个很好的好处是它违反了单一责任原则,这是非常明显的.

当发生这种情况时,是时候重构Facade Services了.简而言之,创建一个新的,更粗粒度的界面,隐藏您当前需要的部分或全部细粒度依赖关系之间的交互.

  • 最好的评论:"构造函数注入的一个很好的好处是它违反了单一责任原则,这是非常明显的." (89认同)
  • 真的?你刚刚创建了一个间接将这些参数移动到另一个类中,但它们仍然存在!处理它们会更复杂. (46认同)
  • @irreputable:在我们将*all*dependencies移动到聚合服务的退化情况下,我同意它只是另一个间接层没有任何好处,所以我选择的单词略有偏差.但是,关键是我们只将*一些细粒度的依赖项移动到聚合服务中.这限制了新聚合服务和遗留的依赖项中的依赖项排列的数量.这使得处理起来更简单. (20认同)
  • +1用于将重构工作量化为单个概念; 太棒了:) (8认同)
  • @DonBox在这种情况下,您可以编写空对象实现来停止递归。不是您所需要的,但重点是构造函数注入并不能防止循环-只能清楚地知道它们在那里。 (2认同)

der*_*ion 60

我不认为你的类构造函数应该引用你的IOC容器周期.这表示您的类和容器之间不必要的依赖关系(IOC试图避免的依赖类型!).


kyo*_*ryu 25

传递参数的难度不是问题.问题是你的班级做得太多了,应该分解得更多.

依赖注入可以作为类太大的早期警告,特别是因为传递所有依赖项的痛苦越来越大.

  • 如果我错了,请纠正我,但在某些时候你必须"将所有东西粘在一起",因此你必须得到更多的依赖.例如,在View层中,为它们构建模板和数据时,您必须从各种依赖项(例如"服务")中获取所有数据,然后将所有这些数据放入模板和屏幕中.如果我的网页有10个不同的"块"信息,那么我需要10个不同的类来为我提供这些数据.所以我需要10个依赖项进入我的View/Template类? (38认同)

tch*_*dze 5

问题 :

1) 参数列表不断增加的构造函数。

2) 如果类是继承的(例如:)RepositoryBase,则更改构造函数签名会导致派生类发生更改。

解决方案1

传递IoC Container给构造函数

为什么

  • 不再增加参数列表
  • 构造函数签名变得简单

为什么不

  • 使您的类与 IoC 容器紧密耦合。(当 1. 你想在使用不同 IoC 容器的其他项目中使用该类时,这会导致问题。2. 你决定更改 IoC 容器)
  • 让你的课堂不再那么具有描述性。(你不能真正查看类构造函数并说出它的功能需要什么。)
  • 类可以访问所有服务。

解决方案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;
    }
  }
Run Code Online (Sandbox Code Playgroud)

派生类

  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;
      }
   }
Run Code Online (Sandbox Code Playgroud)

为什么

  • 向类添加新的依赖项不会影响派生类
  • 类与 IoC 容器无关
  • 类是描述性的(就其依赖性而言)。按照惯例,如果您想知道A依赖于哪个类,该信息会累积在A.Dependency
  • 构造函数签名变得简单

为什么不

  • 需要创建额外的类
  • 服务注册变得复杂(需要单独注册X.Dependency
  • 概念上与传递相同IoC Container
  • ..

解决方案 2 只是一个原始方案,如果有确凿的论据反对它,那么描述性评论将不胜感激