SOLID: The Liskov Substitution Principle (LSP)

Introduction

Robert C. Martin coined the mnomonic acronym SOLID to represent 5 principles of software design. This is the third in my own five-part series exploring my understanding of and experience applying these principles:

1. [SRP] The Single-Responsibility Principle:
• "Software entities should have only one reason to change."
2. [OCP] The Openâ€“Closed Principle:
• "Software entities should be 'open for extension but closed for modification'."
3. [LSP] The Liskov Substitution Principle: (you are here)
• "Subtypes must be substitutable for their base types."
4. [ISP] The Interface Segregation Principle:
• "Clients should not be forced to depend on methods they do not use."
5. [DIP] The Dependency Inversion Principle:
• "High-level policy should depend upon abstractions, not concretions."

LSP

This principle is mostly concerned with the potential for voliating invariants when using inheritance to define a heirachy. The example below is in Go, which doesn't really have traditional inheritance, but does support a concept called embedding, which is simliar:

``````type Rectangle struct {
TopLeft Point
Length  int
Width   int
}

type Square struct {
Rectangle
}
``````

In this example, the `Square` struct embeds the `Rectangle`. This is probably because the developer who wrote this code was used to thinking of a square being a special case of rectangle, which can often indicate a good candidate for sub-classing and inheritance. 'Under the hood', there's an actual field on the `Square` of type `Rectangle`, but you can access the `Rectangle` fields (and methods, if any are defined) as if they were defined on the `Square`.

``````func main() {
s := Square{
Rectangle: Rectangle{
TopLeft: Point{0, 0},
Length:  4,
Width:   4,
},
}
fmt.Println(s.Length, s.Width) // Output: 4 4
}
``````

But the embedding of Rectangle to represent a Square is...not good:

``````func main() {
s := Square{
Rectangle: Rectangle{
TopLeft: Point{0, 0},
Length:  4,
Width:   4,
},
}
s.Length = 5
fmt.Println(s.Length, s.Width) // Output: 5 4
}
``````

Well, that's awkward, a word which here means a violation of LSP.

Next Section: The Interface Segragation Principle