I have a number Processor
classes that will do two very different things, but are called from common code (an "inversion of control" situation).
I'm wondering what design considerations I should be cognicent (or cognizant, for you USsers) of when deciding if they should all inherit from BaseProcessor
, or implement IProcessor
as an interface.
Generally, the rule goes something like this:
To put this in somewhat more concrete terms, let's look at an example. The System.Drawing.Bitmap
class is-an image (and as such, it inherits from the Image
class), but it also can-do disposing, so it implements the IDisposable
interface. It also can-do serialization, so it implements from the ISerializable
interface.
But more practically, interfaces are often used to simulate multiple inheritance in C#. If your Processor
class needs to inherit from something like System.ComponentModel.Component
, then you have little choice but to implement an IProcessor
interface.
The fact is that both interfaces and abstract base class provide a contract specifying what a particular class can do. It's a common myth that interfaces are necessary to declare this contract, but that's not correct. The biggest advantage to my mind is that abstract base classes allow you provide default functionality for the subclasses. But if there is no default functionality that makes sense, there's nothing keeping you from marking the method itself as abstract
, requiring that derived classes implement it themselves, just like if they were to implement an interface.
For answers to questions like this, I often turn to the .NET Framework Design Guidelines, which have this to say about choosing between classes and interfaces:
In general, classes are the preferred construct for exposing abstractions.
The main drawback of interfaces is that they are much less flexible than classes when it comes to allowing for the evolution of APIs. Once you ship an interface, the set of its members is fixed forever. Any additions to the interface would break existing types implementing the interface.
A class offers much more flexibility. You can add members to classes that you have already shipped. As long as the method is not abstract (i.e., as long as you provide a default implementation of the method), any existing derived classes continue to function unchanged.
[ . . . ]
One of the most common arguments in favor of interfaces is that they allow separating contract from the implementation. However, the argument incorrectly assumes that you cannot separate contracts from implementation using classes. Abstract classes residing in a separate assembly from their concrete implementations are a great way to achieve such separation.
Their general recommendations are as follows:
Chris Anderson expresses particular agreement with this last tenet, arguing that:
Abstract types do version much better, and allow for future extensibility, but they also burn your one and only base type. Interfaces are appropriate when you are really defining a contract between two objects that is invariant over time. Abstract base types are better for defining a common base for a family of types.