This article covers the L
When is a Spade not a spade?
It’s summer time and the garden is looking a little bit neglected. It’s time to do a bit of gardening and add a border to the lawn but we’re much too clever to do all the hard work ourselves, not when we have RoboSlave ready, willing and waiting for our every command.
We’re going to need some seeds, some compost and a spade to dig out the border so we send RoboSlave on his merry way to a DIY store to pick up the things we need.
After the shop assistant gets over the shock of serving a robot, RoboSlave comes back with his new purchases and presents them for inspection.
Imagine your surprise when RoboSlave hands you a pack of playing cards. What’s that RoboSlave? It contains spades, hearts, diamonds and clubs, he replies. That wasn’t what I meant by a spade RoboSlave, bad slave, no WD40 for you tonight!
Later I explain, this may be called a spade RoboSlave, but it doesn’t have all the properties I’d expect a spade to have. It doesn’t have a handle and it would be of no use when digging out those borders.
That whole misunderstanding is pretty much what the Liskov substitution principle is all about. We shouldn’t create a class as a subtype of another class unless the class conforms to how we’d expect the parent class to behave. We should be able to swap sub-type A for sub-type B without losing any of the functionality the parent type promises.
Another example would be a rubber duck. A rubber duck isn’t really a duck at all, it doesn’t taste good with orange sauce and it doesn’t quack (it squeaks) and it doesn’t have feathers either. The only thing a rubber duck has in common with a real duck is that it floats on top of water.
Although inheritance is a useful way of reusing code, we often find that it is better to extend some given functionality with composition instead whereby, instead of creating a sub class, we have a class that contains a property of another type that provides the additional functionality and we can provide a concrete version of that type at runtime, meaning we can substitute it for another one that meets that need.
For example, for our back garden we may have a class called
BorderMaker that accepts a parameter of type
IDigThis that provides a method called
Dig() and then we could substitute the
IDigThis object with a trawl, a spade or even a JCB depending on the size of our garden.
In the next post, we will look at the I in Solid, Interface Segregation Principle.