注入具有与更高级别类相同的构造函数参数的依赖项

时间:2018-08-13 07:22:41

标签: c# design-patterns dependency-injection

有时在设计类时,我需要一些具有相似构造函数参数的依赖类。假设我们有

interface IDependency {
    void DoSomething();
}

class DependencyClass : IDependency {
    public DependencyClass(int length) {...}
    ...
}

class MainClass {
    public MainClass(int length, IDependency dependency) {...}
    ...
}

MainClass需要具有相同DependencyClass的{​​{1}}实例。我有两种处理方法:

  1. 不直接创建length的实例,而总是从工厂获取它们。这样,我可以确保将所需的MainClass实例提供给IDependency构造函数。

  2. 将工厂接口(例如MainClass而不是IDependencyFactory传递给MainClass构造函数。这样我就可以在自己的IDependency实现中获取DependencyClass的所需实例。

我不确定它们中的任何一个是否是一个不错的选择。在这种情况下是否有最佳做法?

3 个答案:

答案 0 :(得分:5)

这是一个非常有趣的问题,答案取决于您在此处尝试实现的目标。

解决方案1。。您提供的IDependency将成为工厂的主要接口,所有实例将通过IDependency接口实现,这将为您提供很多可扩展性-将来,您将可以使用IDependency接口使用不同的功能来初始化其他类,这是工厂设计模式的经典用法和实现。

解决方案2 。您提供的MainClass将使程序的Main Class变得更好,您将在Main Class中处理实例及其行为,这样做的好处是您可以通过IDependency管理所有实例,而在MainClass中要做的唯一事情就是处理它们的逻辑,MinaClass将是您的实例传输器,以及对基础的所有基本更改将在接口IDependency中创建类,这是依赖倒置的经典解决方案。

问题仍然存在,您要实现什么目标。考虑一下这个问题和两种可能性,您就会得到答案。

答案 1 :(得分:3)

如果您的length是运行时变量,请参考this comment

如果在运行时需要此功能,则可以使用this answer中的解决方案#2。

如果它是编译时间设置,则可以将其作为任何其他依赖项注入,这MainClassDependencyClass都依赖于同一值是正常的。

要获得安全的编译时注入,可以引入如下内容:

interface ILength {
    int Length { get; }
}

class StaticLength : ILength {
    public StaticLength(int length) {
        Length = length;
    }
}

void Main() {
    const int length = 10;
    ILength lengthDependency = new StaticLength(length);
    IDependency dep = new DependencyClass(lengthDependency);
    MainClass mainClass = new MainClass(lengthDependency, dep); 
}

现在您可以实现任何种类的ILength-从配置文件,常量,Web,模拟,基于其他任何依赖项,随机值的计算中读取。

答案 2 :(得分:3)

为保证DepencyClassMainClass的长度相同,您可以做的最简单的更改之一就是在接口中添加一个Length属性并对其进行初始化。从构造函数中访问,然后允许MainClass访问长度(然后在MainClass上保存一个参数,该参数将更多DRY

interface IDependency {
    int Length { get; }
    void DoSomething();
}

class DependencyClass : IDependency {
public DependencyClass(int length) { Length = length; }
    ...
}

class MainClass {
    public MainClass(IDependency dependency) {...}
    ...
    // do something with dependency.Length
}

这确实有可能会“污染”您的界面,并可能使长度暴露给其他代码。如果那很重要,则取决于您。