In a recent discussion with colleagues the question was asked why we would use interfaces in a system where we generally will have only one implementation of the interface. This applies to things such as services but also to repositories and other infrastructure pieces. The question is legitimate, it does seem like additional overhead to maintain the interfaces when there are not going to be multiple implementations at runtime. The answer has to do with coupling and the nature of statically typed languages, in particular C# and the design choices made when creating the language.

Where a class A has a dependency B there are many ways to implement this relationship. The most direct is for A to new an instance of B. This method has extremely high coupling and is generally undesirable. The next step would be to use one of the classic Gang of Four Factory patterns. This isolates A from the complexities of instantiating B but doesn’t do a huge amount to break the coupling other than remove that specific to the creation of instances of B. A is still aware of the existence of B and is directly exposed to the contract B provides.

What we really need is to provide an abstraction that defines the contract B supports to provide its function but that does not expose the implementation details of B. A can then use this abstraction to interact with an instance of B to support its own functionality. However if the instance is changed to another type C then A does not need to be aware of this change provided that C correctly implements the contract. A may obtain the abstraction from a factory or through a mechanism such as dependency injection and therefore has the coupling with the specific instance B or C broken. The coupling is now to a more generic contract that is focused only on the concerns that A and B share.

With C# there are two possible ways to provide this contract. We may create a base class that possesses abstract or virtual methods that define the contract or we may use interfaces. There are different benefits and costs of each and therefore no one single approach is always preferable.

Use of a base class is advantageous if you have common logic that multiple implementations of the contract will wish to share. Additionally a base class makes it easier to extend the contract without breaking existing derived types as a default implementation may be supplied. This approach is popular with Microsoft for this reason as they can expect many third parties to provide custom implementations of their contracts. The downside of a base class is that it burns the single class from which a type may inherit which can significantly limit how the contract may be implemented to fit with other systems which may have their own classes to derive from.

It would be possible to make the existing implementation virtual and allow new implementations to override it. With our example above this would involve making the appropriate methods in B virtual and having C derive from B. This would be poor practice and is not recommended. In this case C would carry all the concerns of B, even if they are not relevant. this represents overhead and additional complexity in constructing C that are potentially of no benefit. It would be better to have a common base which contains the common implementation which B and C then customise as appropriate without having to consider each others concerns.

Interfaces are pure contract and are therefore more suitable when only a contract is required to be shared. They are also virtual by default, which is not true of class methods. This means that the behaviour a type implementing an interface supplies is entirely customisable and is not in any way fixed or restricted by a base type. The obvious downside is that all the behaviour must be supplied by the implementing type. Whether this is a drawback will depend on whether there is a need to share such behaviour. In many cases where an interface is used to break coupling this will not be an issue. Interfaces may also be more limiting when third parties create types that implement them (or where a system has many implementations of the interface) as changing an interface is always a breaking change.

It is possible to combine the two approaches by providing an interface and an implementation of the interface that may be derived from. Provided the system relies only on the interface a choice is then provided as to whether to use the implementation and take advantage of the common functionality or to gain flexibility at the cost of additional effort by implementing the interface. This does not eliminate the problem of breaking changes due to modifying the interface but may alleviate the issue for types that derive from the base implementation.

In defining the contracts for services in a business application I generally favour interfaces, for the following reasons:

  • Services will generally have a single implementation. The interface is to reduce coupling and make the contract explicit, not to allow substitution on implementations at runtime. This means it does not need to carry shared behaviour
  • Interfaces are virtual by default which eliminates issues due to the non-virtual default for methods in C#.
  • Services should generally not have a default behaviour if an implementation is not provided. This means that a base type may be actively harmful. Interfaces ensure that a behaviour must be provided (but does not ensure that it does anything useful).

Modern IDEs make the maintenance of interfaces a relatively low overhead which is significantly outweighed by the benefits of breaking coupling. Alternatively you could switch to a duck-types language where the static typing concerns that drive much of the above disappear.