什么时候使用 DI 而不是抽象继承?

When to use DI over abstract inheritance?

我正在设计一个 class,它使用抽象 属性 来提供对字段的访问点。这是我的代码片段:

public abstract class PageBroker : WebBroker
{
    public abstract IPageProvider Provider { get; }
}

public class ArticleBroker : PageBroker
{
     public override IPageProvider Provider { get; } = new ArticleProvider();
}

我意识到我可以将其重构为使用 DI,如下所示:

public class PageBroker : WebBroker
{
    public PageBroker(IPageProvider provider)
    {
        this.Provider = provider;
    }

    public IPageProvider Provider { get; private set; }

    // implementation...
}

// no derived class, just new PageBroker(new ArticleProvider())

在什么情况下一种技术比另一种更合适?

这是关于支持组合而不是继承,这是一个很好的指导方针。我建议,由于 PageBroker IPageProvider,您应该使用 DI。 class 的用户可以提供没有继承的替代实现,比如注入一个测试 IPageProvider。仅出于这个原因,我会选择 DI。

如果存在基于 IPageProvider 的存在差异,以至于在语义上使用不同的提供者需要来反映关系(a PageBroker 的子类型),那么我会使用抽象 class.

如前所述,我将使用 DI 填充您的 Provider。也就是说,您希望通过摘要 class 获得什么?如果只是简单的注入IPageProvider那就真的没什么好说的了。

但是,如果您有其他针对 WebBrokers 或 PageBrokers 的常用方法,那么为什么不同时使用这两种方法呢?

例如:

public abstract class WebBroker
{
    private IPageProvider _pageProvider;

    protected WebBroker(IPageProvider pageProvider)
    {
        _pageProvider = pageProvider;
    }

    public override void CommonThing(int someData)
    {
       var result = _pageProvider.CommonMethod(someData);
       //do something with result
    }
}

现在您所有的 WebBroker 都有使用 DI 传入的 _pageProvider 的 CommonThing 方法。

我同意 BJ Safdie 的回答。

也就是说,我认为主要区别在于,在第一个实现中,ArticleBroker 耦合到 IPageProvider(即 ArticleProvider)的特定实现。如果这是有意的,我认为没有问题。但是,如果您想在运行时提供 IPageProvider 的实现(在生产代码中或通过 mocks/fakes 在单元测试中),那么注入依赖项是更好的选择。