When to use DI over abstract inheritance?

164 Views Asked by At

I am designing a class that uses an abstract property to provide a point of access to a field. Here is a snippet of my code:

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

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

I realized I could refactor this to use DI instead, like so:

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())

In what situation(s) would one technique be appropriate over the other?

3

There are 3 best solutions below

0
On BEST ANSWER

I agree with BJ Safdie's answer.

That said, I think the main difference is that in the first implementation, ArticleBroker is coupled to a specific implementation of IPageProvider (namely ArticleProvider). If this is intended, I see no problem with it. However, if you want to provide an implementation of IPageProvider at runtime (either in production code or in a unit test via mocks/fakes), then injecting the dependency is the better choice.

0
On

As already stated I would populate your Provider with DI. That said what are you looking to gain via the abstract class? If it is simply to inject the IPageProvider then there is really nothing more to say.

If however you have other common methods in mind that are very specific to WebBrokers or PageBrokers then why not use both?

For example:

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
    }
}

Now all your WebBrokers have the CommonThing method which uses the _pageProvider that DI passed in.

0
On

This is about favoring composition over inheritance, which is a good guideline. I would suggest that since the PageBroker has an IPageProvider, you should use DI. Users of the class can provide alternate implementations without inheritance, say to inject a test IPageProvider. For this reason alone, I would go with DI.

If there is an existential difference based on IPageProvider such that using a different provider semantically needs to reflect an is a relationship (a subtype of PageBroker), then I would go with an abstract class.