Interfaces and abstract classes in .NET are pretty similar in functionality - you can't instantiate them, but still objects of various runtime types can hide both behind an interface or behind an abstract class. So when to use which?
The "
Framework Design Guidelines" book by
Brad Abrams and
Krzysztof Cwalina is a very good book for all those who like asking such questions. Particularly, there is a whole section 4.3 "Choosing between class and interface" discussing this issue. I'll spoil the plot ending and post the main advice right away:
Do favor defining classes over interfaces.
The main argument of the authors is flexibility of classes. This applies mostly to layered architectures, where a client layer uses the framework layer. Classes can provide default implementation, so even if you already have derived classes in your client layer and you're adding a new virtual method to your base class in the framework, the clients won't even have to recompile their derived classes - the new virtual method magically appears in the derived types automatically and you don't have to change anything in the client. On the contrary, if you add a new method to an interface, which is already being implemented by some clients, you can't provide the default implementation - it would introduce a breaking change (all clients would have to manually add methods to implement the new method of the interface).
This is a very good point - once you ship an interface you basically can't change it anymore - it's carved in stone starting from the very moment anyone on the client side implements it. Unless you want to break that client and make them recompile or even worse - re-deploy.
When I was developing an editor for C# it was based on a framework for editors. During design of the framework and the editor, I learned a lot about how to use interfaces (more precisely, how
not to use them). Now I want to share my experiences with you to add a couple of measly cents to the dollars of wisdom of .NET architects.
My whole editor framework is built around a concept of a 'block' - a rectangular thing which can be displayed on the screen and contain text and other blocks. The framework is basically a hierarchy of classes that inherit from the
Block class. If you're familiar with the
Composite design pattern and the text editor example from the
GoF book, you'll immediately recognize that blocks are simply
Glyphs - basic elements from which documents are composed. Now, I had an interface
IBlock and an abstract class
Block, which implemented
IBlock. As it turned out many lines of code later, this was the most stupid thing to do:
- Anytime I wanted to add new members to the class hierarchy, I had to update both the base class and the interface
- Once I'd ship the IBlock interface and a client would implement it, I wouldn't be able to add anything to it anymore
- The only situation where IBlock would be useful is when some client would want to implement it without inheriting from Block - and who on earth would ever want that?
I removed the
IBlock interface and changed all its usages to use the abstract class
Block instead. This simplified my life so much.
What I've learned from this: interfaces are good when you want to work with some distinguished
feature or
ability of an entity, and not the whole entity. For example, if you want to enumerate something, it is sufficient for you to receive an
IEnumerable - you don't care about the rest of the entity. It can be anything, of any complexity - for you is only important that it allows to enumerate itself. A good occasion to use an interface is having many base classes - you don't have to inherit from Collection, you have various base classes and the only thing you have to do is to implement IEnumerable. As I said, interfaces describe
part of the functionality, and you can
mix-in this functionality to existing class hierarchies without adding a new base class.
Classes, on the opposite, are good for modeling whole entities, entire complete entities as a whole. That was my mistake - I used an interface for the whole entity "Block", where I should have used a class instead. With classes, you can't mix in a new base class to an existing one - that would mean merging two clearly separate stand-alone entities into some weird-looking hybrid. That is one of the reason multiple inheritance is not allowed in .NET - you shouldn't mix entities together, it's not a good practice. On the opposite, you should do your best to separate your entities from one another. It's like normalization of relational databases - you split your tables until each table describes a clearly defined entity with exact boundaries and strictly defined connections and relationships to other entities.
A common design mistake is called "burning the base class" - it's when you make your whole hierarchy inherit from some base class just to add some functionality to the entire class hierarchy in one simple step. As a rule, this functionality doesn't represent a separate, stand-alone entity, but still you waste your base class to add partial functionality. As I said before, interfaces are best when you want to add part of a functionality - you can mix it in to an existing hierarchy without burning the base class. An example of burning the base class is a System.MarshalByRefObject from the .NET base class library. Clearly, we waste a base class of all Windows Forms controls just to add some
ability to all the classes at once. Adding an ability is done best by interfaces. However, this way requires more typing because an interface can't provide a default implementation.
To reiterate: use classes to model whole entities, and use interfaces to add abilities to existing entities. The only exception to this rule I can currently think of - is when you don't want your entities to be extended in the future. That is, you'd like to specify a precise contract for an entity, and you can guarantee that this entity won't have additional abilities in the future - at least not in your scope. Then, it's OK to use an interface to capture the entity and carve it in stone. Clients are free to add functionality to this entity, but you don't want to see it in your framework. You'll only work with this strictly defined entity and it's not going to change.
Finally, I've discovered a rule of thumb for myself which generally helps me to use interfaces correctly.
An interface should define at most one member. Yes, that easy. One could even have an FxCop rule for it. If you want to define an
ability on some entity, one member is mostly enough: GetEnumerator() for an enumerable, Clear() for a clearable, Count for countable and so on and so forth. If you want a more complex ability or a composed entity, use interface inheritance:
ICollection : IAllowsAdd, IAllowsRemove, IEnumerable, IClearable, Indexable, ICountable, ISet
Purists can push this rule even further:
An interface can either:- declare no members and inherit from no interfaces ("a marker interface"), or
- declare a single member, or
- inherit from two other interfaces.
This would be some minimal "interface normal form" à la
Chomsky, to which any interface hierachy could be reduced. Unfortunately, this mathematically beautiful "normal form" wouldn't be practical for everyday development.