What is LSP?Source: email@example.com
Stephen R. Tockey wrote:
LSP = "Liskov Substitutability Principle" and is described in detail in:
Barbara Liskov and Jeanette Wing, "A Behavioral Notion of Subtyping", ACM Transactions on Programming Languages and Systems, Vol 16, No 6, November, 1994, pages 1811-1841.Quoting from the abstract of the paper:
"The use of hierarchy is an important component in object- oriented design. Hierarchy allows the use of type families, in which higher level supertypes capture the behavior that all of their subtypes have in common. For this methodology to be effective, it is necessary to have a clear understanding of how subtypes and supertypes are related. This paper takes the position that the relationship should ensure that any property proved about supertype objects also holds for subtype objects..."Very simply put, LSP states that "objects of the subtype ought to behave the same as those of the supertype as far as anyone or any program using supertype objects can tell". In other words I ought to be able to substitute any subtype of class X in a program that expects a member of class X and the program should still behave reasonably.
[Or as Bertrand Meyer said: A subtype must require no more and promise no less than its supertype.]
In order for this to work, substitutability has to be based on more than just signature (i.e., just because class X and class X' have identical sets of methods with identical parameters does not guarantee that I can expect my program to be well-behaved if I substitute a member of class X' where my program expects a member of class X).
In an abstract (i.e., non-implementation-specific) sense, we need to consider things like those methods' pre-conditions (what must be true before invoking the method to guarantee that the method will result in "a right answer") and post-conditions (what the method guarantees to be true on its completion). In order for class X' to be a subtype of class X, the pre-conditions of the methods of the supertype must be at least as restrictive (but possibly more) than the pre-conditions of the corresponding methods of the subtype(s) AND/OR the post-conditions of the methods of the subtype must be at least as restrictive (but possibly more) than the post- conditions of the corresponding methods on the supertype.
Consider a class GeometricShape together with classes CircleShape and SquareShape. Assume all classes offer the method Draw(). It should make sense that the pre-conditions and post-conditions of Draw() on each of these classes are quite similar (e.g., pre- condition is that a graphics pane is open and the X,Y coordinates of the shape are within the boundary of that graphics pane. For a GeometricShape, the post-condition is that some figure has been drawn into the graphics pane. For the CircleShape and SquareShape the post-conditions might be that a circle or a square (respectively) has been drawn in the graphics pane. According to LSP, CircleShape and SquareShape can be considered subtypes of GeometricShape and I can safely substitute a member of CircleShape or SquareShape anywhere my program expects a member of GeometricShape (at least as far as this example is concerned).
As another example, consider GeometricShape and WildWestGunfighter. Assume both classes offer the method Draw(). It should make sense that the pre-conditions and post-conditions of Draw() on a GeometricShape (pre: graphics pane open & coordinates in pane, post: shape has been drawn) are quite different from the pre-conditions and post-conditions of Draw() on a WildWestGunfighter (pre: gun is loaded and in holster on hip & adversary is in sight, post: shot has been fired at adversary). Therefore, according to LSP, WildWestGunfighter is not a subtype of GeometricShape and I should not expect a program to be well behaved if I substitute a member of WildWestGunfighter in a place where the program expected a GeometricShape.
Robert C. Martin, The Liskov Substitution Principle (PDF)
Bertrand Meyer, An Introduction to Design by Contract