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

8 Answers 8

up vote 16 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 like the sound of this answer but don't quite follow the last part. You're suggesting that BetterBaseWorker would be an independent abstract class that implements IFooWorker, so that my hypothetical plugin could simply say "oh boy! The Better Base Worker is finally out!" and change any BaseWorker references to BetterBaseWorker and call it a day (maybe play with the cool new returned values that let me strip out huge chunks of my redundant code, etc)? –  Anthony May 15 at 11:26
    
More or less, yes. The big advantage is that you will reduce the number of references to BaseWorker that will have to change to be BetterBaseWorkers instead; most of your code won't reference the concrete class directly, instead using IFooWorker, so when you change what is assigned to those IFooWorker dependencies (properties of classes, parameters of constructors or methods) the code using the IFooWorker shouldn't see any difference in usage. –  KeithS 2 days ago

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

I am still years away from fully grasping the distinction between an abstract class and an interface. Every time I think I get a handle on the basic concepts, I go looking on stackexchange and I'm two steps back. But a few thoughts on the topic and the OPs question:

First:

There are two common explanations of an interface:

  1. An interface is a list of methods and properties that any class can implement, and by implementing an interface, a class guarantees those methods (and their signatures) and those properties (and their types) will be available when "interfacing" with that class or an object of that class. An interface is a contract.

  2. Interfaces are abstract classes that don't/can't do anything. They're useful because you can implement more than one, unlike those mean parent classes. Like, I could be an object of class BananaBread, and inherit from BaseBread, but that doesn't mean I can't also implement both the IWithNuts and the ITastesYummy interfaces. I could even implement the IDoesTheDishes interface, because I'm not just bread, yknow?

There are two common explanations of an abstract class:

  1. An abstract class is, yknow, the thing not what the thing can do. It's like, the essence, not really a real thing at all. Hang on, this will help. A boat is an abstract class, but a sexy Playboy Yacht would be a sub class of BaseBoat.

  2. I read a book on abstract classes, and maybe you should read that book, because you probably don't get it and will do it wrong if you haven't read that book.

By the way, the book Citers always seem impressive, even if I still walk away confused.

Second:

On SO, someone asked a simpler version of this question, the classic, "why use interfaces? What's the difference? What am I missing?" And one answer used an air force pilot as a simple example. It didn't quite land, but it sparked some great comments, one of which mentioned the IFlyable interface having methods like takeOff, pilotEject, etc. And this really clicked for me as a real-world example of why interfaces are not just useful, but crucial. An interface makes an object/class intuitive, or at least gives the sense that it is. An interface isn't for the benefit of the object or the data, but for something that needs to interact with that object. The classic Fruit->Apple->Fuji or Shape->Triangle->Equilateral examples of inheritance are a great model for taxonomically understanding a given object based on its descendants. It informs the consumer and the processors about its general qualities, behaviors, whether the object is a group of things, will hose your system if you put it in the wrong place, or describes sensory data, a connector to a specific data store, or financial data needed to make payroll.

A specific Plane object may or may not have a method for an emergency landing, but I'm going to be pissed off if I assume its emergencyLand like every other flyable object only to wake up covered in DumbPlane and learn that the developers went with quickLand because they thought that it was all the same. Just like how I would be frustrated if every screw manufacturer had their own interpretation of righty tighty or if my TV didn't have the volume increase button above the volume decrease button.

Abstract classes are the model that establishes what any descendent object must have to qualifiy as that class. If you don't have all the qualities of a duck, it doesn't matter that you have the IQuack interface implemented, your just a weird penguin. Interfaces are the things that make sense even when you can't be sure of anything else. Jeff Goldblum and Starbuck were both able to fly alien spaceships because the interface was reliably similar.

Third:

I agree with your coworker, because sometimes you need to enforce certain methods at the very start. If you're creating an Active Record ORM, it needs a save method. This isn't up to the subclass that can be instantiated. And if the ICRUD interface is portable enough to not be exclusively coupled to the one abstract class, it can be implemented by other classes to make them reliable and intuitive for anyone already familiar with any of the descendant classes of that abstract class.

On the other hand, there was a great example earlier of when to not jump to tying an interface to the abstract class, because not all list types will (or should) implement a queue interface. You said this scenario happens half the time, which means you and your coworker are both wrong half the time, and thus the best thing to do is argue, debate, consider, and if they turn out to be right, acknowledge and accept the coupling. But don't become a developer who follows a philosophy even when it isn't not the best one for the job at hand.

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.