In this five-part series, I’m covering each design principle laid out in SOLID. In this post, I am covering the Liskov substitution principle.
Now is when things get interesting: program to an interface that can be implemented by many services.
The Liskov substitution principle (LSP), created by Barbara Liskov, says we can substitute one service for another.
For example, let’s say you have two classes with each inheriting from a common base. By following LSP, you could create a method that could accept either of those derived classes, assuming that base call as a parameter.
We don’t want to use a lot of inheritance; we prefer the concept of interfaces. Why interfaces?
In general, we want to keep separate concerns separate. We like to keep data (data contracts) separate from behavior (services). We can also follow that pattern for the definition of a service by keeping the definition separate from the implementation.
By keeping the definition (interface) separate from the implementation, we can hand that interface to anyone and ask them to build it. We can even build the interface solely for the purpose of mocking. We can create a mock version of the interface, and we don’t have to inherit from the full version of the service to do it.
Once inheritance gets involved, you often have to make your code more public than is prudent. In our C# world, we want to keep our C# service implementations private and only createable by our factories.
We must only program against the interface, not the concrete implementation.
LSP is essential for building quality, large software systems. This principle almost enforces a loosely coupled system if you do it right. You can still create a weirdly coupled design, and you can still create some odd coupling to the data passed between services. But when you start using LSP, your chance of creating these problems goes down a lot.