What is the Liskov Substitution Principal?
The Liskov Substitution Principal (LSP) is a concept in Object Oriented Programming that states:
Functions that use pointers or references to base classes must be able to use objects of derived classes with out knowing it. At it's heart LSP is about interfaces and contracts as well as how to decided when to extend a class vs. use another strategy such as composition to achieve your goal.
The most effective way I have seen to illustrate this point was in Head First OOA&D. They present a scenario where you are a developer on a project to build a framework for strategy games.
They present a class that represents a board that looks like this:
All of the methods take X and Y coordinates as parameters to locate the tile position in the two dimensional array of Tiles. This will allow a game developer to manage units in the board during the course of the game.
The book goes on to change the requirements to say that the game frame work must also support 3d game boards to accommodate games that have flight. So a ThreeDBoard class is introduced that extends Board.
At first glace this seems like a good decision. Board provides both the Height and Width properties and ThreeDBoard provides the Z axis.
Where it breaks down is when you look at all the other members inherited from Board. The methods for AddUnit, GetTile, GetUnits and so on, all take both X and Y parameters in the Board class but the ThreeDBoard needs a Z parameter as well.
So you must implement those methods again with a Z parameter. The Z parameter has no context to the Board class and the inherited methods from the Board class lose their meaning. A unit of code attempting to use the ThreeDBoard class as it's base class Board would be very out of luck.
Maybe we should find another approach. Instead of extending Board, ThreeDBoard should be composed of Board objects. One Board object per unit of the Z axis.
This allows us to use good object oriented principals like encapsulation and reuse and doesn't violate LSP.
LSP is a good method for discovering if you are using inheritance poorly. Try it next time you go to extend a class.