I spotted a proposed C# coding-standard which stated "Try to offer an interface with all abstract classes". Does someone know the rationale for this?
The .NET Framework Design Guidelines have some interesting things to say about interfaces and abstract classes.
In particular, they note that interfaces have the major drawback of being less flexible than classes when it comes to the evolution of an API. Once you ship an interface, its members are fixed forever, and any additions will break compatibility with the existing types that implement that interface. Whereas, shipping a class offers much more flexibility. Members can be added at any time, even after the initial version has shipped, as long as they are not abstract. Any existing derived classes can continue to work unchanged. The System.IO.Stream
abstract class provided in the Framework is given as an example. It initially shipped without support for timing out pending I/O operations, but version 2.0 was able to add members that supported this feature, even from existing subclasses.
Thus, having a corresponding interface for each abstract base class provides few additional benefits. The interface cannot be publically exposed, or you're left back at square one in terms of versioning. And if you only expose the abstract base class, there's little gained by having the interface in the first place.
Additionally, the point is often made in favor of interfaces that they allow separating contract from implementation. Krzysztof Cwalina argues that this claim is specious: it incorrectly assumes you cannot separate contracts from implementation using classes. By writing abstract classes that reside in a separate assembly from their concrete implementations, it's easy to achieve the same virtues of separation. He writes:
I often hear people saying that interfaces specify contracts. I believe this is a dangerous myth. Interfaces, by themselves, do not specify much beyond the syntax required to use an object. The interface-as-contract myth causes people to do the wrong thing when trying to separate contracts from implementation, which is a great engineering practice. Interfaces separate syntax from implementation, which is not that useful, and the myth provides a false sense of doing the right engineering. In reality, the contract is semantics, and these can actually be nicely expressed with some implementation.
In general, the guideline provided is DO favor defining classes over interfaces. Again, Krzysztof comments:
Over the course of the three versions of the .NET Framework, I have talked about this guideline with quite a few developers on our team. Many of them, including those who initially disagreed with the guideline, have said that they regret having shipped some API as an interface. I have not heard of even one case in which somebody regretted that they shipped a class.
A second guideline argues that one DO use abstract classes instead of interfaces to decouple the contract from implementations. The point here is that correctly-designed abstract classes still allow for the same degree of decoupling between contract and implementation as interfaces. Brian Pepin's personal perspective is thus:
One thing I've started doing is to actually bake as much contract into my abstract class as possible. For example, I might want to have four overloads to a method where each overload offers an increasingly complex set of parameters. The best way to do this is to provide a nonvirtual implementation of these methods on the abstract class, and have the implementations all route to a protected abstract method that provides the actual implementation. By doing this, you can write all the boring argument-checking logic once. Developers who want to implement your class will thank you.
Perhaps one would do best by revisiting the oft-touted "rule" that a derived class indicates an IS-A relationship with the base class, whereas a class implementing an interface has a CAN-DO relationship with that interface. To make the claim one should always code both an interface and an abstract base class, independent of specific reasons to do so, seems to miss the point.
Without looking at the original article, I would guess that the original author is suggesting it for testability and allow easy mocking of the class with tools like MoQ, RhinoMocks etc.
I always understood Interface-Driven Design (IDD) to involve the following steps in creating a concrete class (in its purest form, for non-trivial classes):
virtual
) implementations for members which are unlikely (but possible) to change. You can also provide appropriate constructors (something not possible at the interface level). Mark all other interface members as abstract.The above process, while long-winded, ensures maximum adherence to the contract you initially lay down, while minimising redundant code in alternative implementations.
This is why I would generally pair an abstract class with an interface.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With