Object-Oriented Design – Interfaces on an Abstract Class

design-patternsinterfacesobject-orientedobject-oriented-design

My coworker and I have different opinions on the relationship between base classes and interfaces. I'm of the belief that a class should not implement an interface unless that class can be used when an implementation of the interface is required. In other words, I like to see code like this:

interface IFooWorker { void Work(); }

abstract class BaseWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker, IFooWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

The DbWorker is what gets the IFooWorker interface, because it is an instantiatable implementation of the interface. It completely fulfills the contract. My coworker prefers the nearly identical:

interface IFooWorker { void Work(); }

abstract class BaseWorker : IFooWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

Where the base class gets the interface, and by virtue of this all inheritors of the base class are of that interface as well. This bugs me but I can't come up with concrete reasons why, outside of "the base class cannot stand on its own as an implementation of the interface".

What are the pros & cons of his method vs. mine, and why should one be used over another?

Best Answer

I'm of the belief that a class should not implement an interface unless that class can be used when an implementation of the interface is required.

BaseWorker fulfills that requirement. Just because you can't directly instantiate a BaseWorker object doesn't mean you can't have a BaseWorker pointer that fulfills the contract. Indeed, that's pretty much the whole point of abstract classes.

Also, it's difficult to tell from the simplified example you posted, but part of the problem may be that the interface and the abstract class are redundant. Unless you have other classes implementing IFooWorker that do not derive from BaseWorker, you don't need the interface at all. Interfaces are just abstract classes with some additional limitations that make multiple inheritance easier.

Again being difficult to tell from a simplified example, the use of a protected method, explicitly referring to the base from a derived class, and the lack of an unambiguous place to declare the interface implementation are warning signs that you are inappropriately using inheritance instead of composition. Without that inheritance, your whole question becomes moot.

Related Topic