Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question
    
Your suggestion very closely resembles to diamond inheritance, which may cause a lot of confusion further down. –  Spoike Sep 6 '12 at 8:54

7 Answers 7

up vote 13 down vote accepted

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.

share|improve this answer
    
+1 for pointing out that just because BaseWorker isn't instantiable directly , doesn't mean a given BaseWorker myWorker doesn't implement IFooWorker. –  Avner Shahar-Kashtan Sep 4 '12 at 19:17
    
I disagree that interfaces are just abstract classes. Abstract classes usually define some implementation details (otherwise an interface would have been used). If those details are not to your liking, you must now change every usage of the base class to something else. Interfaces are shallow; they define the "plug-and-socket" relationship between dependencies and dependents. As such, tight coupling to any implementation detail is no longer a concern. If a class inheriting the interface is not to your liking, strip it out and put in something else entirely; your code could care less. –  KeithS Sep 4 '12 at 21:10
1  
They both have advantages, but typically the interface should always be used for the dependency, whether or not there is an abstract class defining base implementations. The combination of interface and abstract class gives the best of both worlds; the interface maintains the shallow surface plug-and-socket relationship, while the abstract class provides the useful common code. You can strip out and replace any level of this underneath the interface at will. –  KeithS Sep 4 '12 at 21:14

I'd have to agree with your coworker.

In both examples you give, BaseWorker defines the abstract method Work(), which means that all subclasses are capable of meeting IFooWorker's contract. In this case, I think BaseWorker should implement the interface, and that implementation would be inherited by its subclasses. This will save you from having to explicitly indicate that each subclass is indeed an IFooWorker (the DRY principle).

If you weren't defining Work() as a method of BaseWorker, or if IFooWorker had other methods that subclasses of BaseWorker wouldn't want or need, then (obviously) you'd have to indicate which subclasses actually implement IFooWorker.

share|improve this answer
8  
+1 would have posted the same thing. Sorry insta, but I think your coworker is right in this case as well, if something guarantees to fulfill a contract, it should inherit that contract, whether the guarantee is fulfilled by an interface, an abstract class, or a concrete class. Simply put: The guarantor should inherit the contract it guarantees. –  Jimmy Hoffa Sep 4 '12 at 17:44
    
I generally agree, but would like to point out that words like "base", "standard", "default", "generic", etc. are code smells in a class name. If an abstract base class has almost the same name as an interface but with one of those weasel words included, it's often a sign of incorrect abstraction; interfaces define what something does, type inheritance defines what it is. If you have an IFoo and a BaseFoo then it implies that either IFoo is not an appropriately fine-grained interface, or that BaseFoo is using inheritance where composition might be a better choice. –  Aaronaught Sep 5 '12 at 2:44
    
@Aaronaught Good point, although it may be that there really is something that all or most of the implementations of IFoo need to inherit (such as a handle to a service or your DAO implementation). –  Matthew Flynn Sep 5 '12 at 4:49
    
Then shouldn't the base class be called MyDaoFoo or SqlFoo or HibernateFoo or whatever, to indicate that it's just one possible tree of classes implementing IFoo? It's even more of a smell to me if a base class is coupled to a specific library or platform and there's no mention of this in the name... –  Aaronaught Sep 6 '12 at 0:24
    
@Aaronaught - Yes. I agree completely. –  Matthew Flynn Sep 6 '12 at 0:58

I generally agree with your coworker.

Let's take your model: the interface is implemented only by the child classes, even though the base class also enforces the exposure of IFooWorker methods. First off, it's redundant; whether the child class implements the interface or not, they are required to override the exposed methods of BaseWorker, and likewise any IFooWorker implementation must expose the functionality whether they get any help from BaseWorker or not.

This additionally makes your hierarchy ambiguous; "All IFooWorkers are BaseWorkers" is not necessarily a true statement, and neither is "All BaseWorkers are IFooWorkers". So, if you want to define an instance variable, parameter, or return type that could be any implementation of either IFooWorker or BaseWorker (taking advantage of the common exposed functionality which is one of the reasons to inherit in the first place), neither of these is guaranteed to be all-encompassing; some BaseWorkers won't be assignable to a variable of type IFooWorker, and vice versa.

Your coworker's model is much easier to use and to replace. "All BaseWorkers are IFooWorkers" is now a true statement; you can give any BaseWorker instance to any IFooWorker dependency, no problems. The opposite statement "All IFooWorkers are BaseWorkers" is not true; that allows you to replace BaseWorker with BetterBaseWorker and your consuming code (which depends on IFooWorker) won't have to tell the difference.

share|improve this answer

I need to add something of a warning to these answers. Coupling the base class to the interface creates a force in the structure of that class. In your basic example, it's a no brainer that the two should be coupled, but that may not hold true in all cases.

Take Java's collection framework classes:

abstract class AbstractList
class LinkedList extends AbstractList implements Queue

The fact that the Queue contract is implemented by LinkedList did not push the concern into AbstractList.

What's the distinction between the two cases? The purpose of BaseWorker was always (as communicated by its name and interface) to implement operations in IWorker. The purpose of AbstractList and that of Queue are divergent, but a descenant of the former can still implement the latter contract.

share|improve this answer
    
This happens half the time. He always prefers to implement the interface on the base class, and I always prefer to implement it on the final concrete. The scenario you presented happens often and is part of the reason interfaces on the base bothers me. –  insta Sep 5 '12 at 18:28
    
Right, insta, and I regard the use of interfaces in this manner as a facet of the inheritance overuse that we see in many development environments. Like the GoF said in their design pattern book, prefer composition over inheritance, and keeping the interface out of the base class is one of the ways of promoting that very principle. –  Mihai Danila Sep 6 '12 at 23:20

First think of what an abstract base class is, and what an interface is. Consider when you would use one or the other and when you would not.

It's common for people to think of both being very similar concepts, in fact it's a common interview question (difference between the two is??)

So an abstract base class gives you something interfaces can't which is default implementations of methods. (There's other stuff, in C# you can have static methods on an abstract class, not on an interface for example).

As an example, one common use of this is with IDisposable. The abstract class implements IDisposable's Dispose method, which means any derived version of the base class will automatically be disposable. You can then play with several options. Make Dispose abstract, forcing derived classes to implement it. Provide a virtual default implementation, so they don't, or make it neither virtual or abstract and have it call virtual methods called things like BeforeDispose, AfterDispose, OnDispose or Disposing for example.

So any time all derived classes need to support the interface, it goes on the base class. If only one or some need that interface it would go on the derived class.

That's all actually a gross over simplification. Another alternative is to have derived classes not even implement the interfaces, but provide them via an adapter pattern. An example of this I saw recently was in IObjectContextAdapter.

share|improve this answer

To start off, I like to define interfaces and abstract classes differently:

Interface: a contract that each class must fulfill if they are to implement that interface
Abstract class: a general class (i.e vehicle is an abstract class, while porche911 is not)

In your case, all workers implement work() because that is what the contract requires them to. Therefore your base class Baseworker should implement that method either explicitly or as a virtual function. I would suggest you to put this method in your base class because of the simple fact that all workers need to work(). Therefore it is logical that your baseclass (even though you cannot create a pointer of that type) includes it as a function.

Now, DbWorker does satisfy the IFooWorker interface, but if there is a specific way that this class does work(), then it really needs to overload the definition inherited from BaseWorker. The reason it should not implement the interface IFooWorker directly is that this is not something special to DbWorker. If you did that everytime you implemented classes similar to DbWorker then you would be violating DRY.

If two classes implement the same function in different ways, you could start looking for the greatest common superclass. Most of the time you will find one. If not, either keep looking or give up and accept that they don't have sufficient things in common to make a base class.

share|improve this answer

I would ask the question, what happens when you change IFooWorker, such as adding a new method?

If BaseWorker implements the interface, by default it will have to declare the new method, even if it's abstract. On the other hand, if it doesn't implement the interface, you'll only get compile errors on the derived classes.

For that reason, I'd make the base class implement the interface, since I might be able to implement all the functionality for the new method in the base class without touching the derived classes.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.