依赖注入&构造函数疯狂修改

时间:2014-07-17 11:34:41

标签: c# design-patterns dependency-injection

在阅读了这个问题How to avoid Dependency Injection constructor madness?后,我仍然对我的应用程序设计有些担忧。假设我有一个类,它的构造函数中包含很少的参数:

public class SampleViewModel
{
    public SampleViewModel(IReader1 reader1, IReader2 reader2, IReader3 reader3)
    {
        // ...
    }
}

IReaderX是一个用于从不同来源检索数据的界面,如下所示:

public interface IReader1
{
    int Value1 { get; }

    string Value2 { get; }
}

现在,如果我想将这些接口聚合为一个,我将不得不创建另一个类,比如ReaderManager,它将充当底层类属性的包装器。很多管道代码。如果你问我,不好。

我尝试使用Composition并将所有读者作为ReaderManager类中的属性,但如果我试图在外面使用这些读者,我会违反Demeter法。

所以问题是:我应该如何减少不相互通信的构造函数依赖项的数量,只暴露属性而不是内部逻辑呢?

1 个答案:

答案 0 :(得分:0)

从几个不同的角度来看待它:消费者和更高层次的设计。


从`SampleViewModel`

的角度来看

不喜欢有这么多的合作者吗?也许如果它有druthers,它只会有一个合作者。那个合作者看起来怎么样?为它创建一个interface to represent the role

例如:

public interface ISampleViewModelReader
{
    int Value1    { get; }
    string Value2 { get; }

    double Value3 { get; }

    string Value4 { get; }
}

public class AggregatedSampleViewModelReader : ISampleViewModelReader
{
    public AggregatedSampleViewModelReader(IReader1 reader1, IReader2 reader2, IReader3 reader3)
    {
        // ...
    }
    // ...
    double Value3 { get { return reader2.Value3; } }
    // ...
}

public class SampleViewModel
{
    public SampleViewModel(ISampleViewModelReader reader)
    {
        // ...
    }
}

您表示您对此方法有疑虑,因为它涉及“大量管道代码”。但请考虑这个管道代码将存在或不存在包装类。通过定义一个包装类,至少你要识别一个对象,它唯一的责任是处理这个管道,而不是将它混合到SampleViewModel的其他职责中。


从更高层次的设计角度来看

其他对象如何使用IReaderX个对象? IReader1IReader2IReader3经常一起使用吗? IReader1IReader3怎么样?

提出这个问题的关键是识别“隐藏的”抽象,以便使它们更加明确。如果某些物体经常串联使用,它通常代表更广泛的设计概念。

但有时a rose is a rose is a rose。也许SampleViewModel是唯一使用IReaderX对象的东西。也许SampleViewModel的唯一责任是聚合个体读者。在这些类型的情况下,拥有多个合作者并没有错。

如果稍后添加了其他协作者(例如IReader4),则应再次进行所有此评估。有时设计恰好跳出来。