Recently I’ve been learning object interfaces and inheritance in the .NET Framework. I understand the technical differences between the two, but how do you apply each of these to a practical situation?
From an object model design standpoint this question stands as one of the core concepts to being able to better understand and design APIs and object models within Microsoft’s .NET Framework. All design patterns make use of interfaces, inheritance or both and by understanding the reasons why a developer might choose one over the other can give the code reader some insight into the developer’s thought process. When we begin designing our own object models and APIs, understanding when and how to use inheritance and when to use interfaces is key to creating an understandable way for other programmers to use what you’ve created. It also doesn’t hurt to be able to demonstrate good object oriented design during interviews with potential employers. There are a few good rules when it comes to making a decision involving interfaces and inheritance.
1. Interfaces should be used to allow for the ultimate customization.
As you design your classes, you should keep in mind how this class and system will be used. If you are to provide the ability for other developers to completely customize the implementation of your object model, then you should have interfaces for any of those classes that could be replaced with something new. This means that you will also have to do what’s called coding to an interface, which is making sure that any parameters on methods that are of a type that could be customized should be specified as the interface type and not the class type. Take, for example, a simple object model that represents a chat room. If we have a ChatServiceClient class that is responsible for sending messages to the server, and a ChatMessage class that represents a single message to be sent, then there should be an interface for the ChatMessage called IChatMessage. The chat service client should then have a method called Send(IChatMessage message). Because the Send method takes the interface as a parameter, we can complete change how we store or use the chat message and never have to worry about changing the Send method.
2. Inheritance is good for modeling evolutionary designs.
By its very definition inheritance is very well suited for modeling evolution-like patterns where our base object is changed slowly through its generations. When you have a strong and direct relationship between your starting point and ending point, inheritance makes more sense. You can provide methods that must be implemented by the derived class in the same way interfaces work, methods that can optionally be implemented by the derived class but have a default implementation in the base class, and methods that are only accessible to the base class. In situations where you want to create a basic template for functionality that will slowly change in derived classes, inheritance is probably the better choice.
3. In .NET, interfaces are the only way to do something similar to multiple inheritance.
For better or worse, Microsoft has decided that it is better to implement multiple interfaces on a given class than to allow developers to inherit multiple classes. Here’s a good answer from StackOverflow user paercebal on why multiple inheritance can be problematic: Why should I avoid multiple inheritance in C++. If you need multiple inheritance, then what you are really saying is that you need interfaces.
The reality of the situation is that when you develop your own object models and APIs, usability is key. If you don’t need or want the users of your object model to have complete customization, then you may consider continuing to use interfaces, but making them internal. This will allow better customization for you as development progresses, but will keep that customization limited to your own code if and until you are ready to make that available to others. You will likely always use a combination of both interfaces and inheritance within your projects, so keep with good design patterns and never stop learning new things about code design.