This is a very interesting article.
Defining a subclass does not break the open/close principle, since it means "open for extension / closed for modification". So:
- One can perfectly add
Penguin subclass to extend
- But changing the interface of the
Bird class to add support for birds that can't fly is definitively a modification.
The Bird class was flawed from the beginning
What does the example shows us ? A very practical case of how to deal with a flawed design. And if the design is not viable, you have to change it.
Bird class was flawed since the beginning, because it didn't take into account the fact that there are birds that can't fly, be it the whole class
Penguin or a single instance of
The class is even more flawed than it seems. Because all birds have ranges of altitude: kingfishers can have a slightly negative altitude under water. And no birds can't fly in the stratosphere: Some species can fly up to 11.300 km but some others are limited to 8.000. And
Penguins are limited between 0 and 0 above the ground (in fact they can dive, so negative altitude is allowed also.
Liskov Substitution Principle in all this ?
Looking at the example code, adding
Penguin to the original
Bird is in fact not a problem according to the LSP, because no promise is made on the result of
The LSP tells us that:
- preconditions cannot be strengthened.
- postconditions cannot be weakened. There is no claim made that the altitude will be set to the value provided, so there's no weakening. If the postconditon is that the new value of altitude is between 0 and the value provided, the extension would match the rules by leaving the altitude unchanged. Btw.us, this post-condition would also allow for
- invariants must be preserved.
- history constraint shall be ensured. This implies that the state and behavior of a
Bird only depend on the use of its defined interface. So for example,
Penguin could have no other method that would change the altitude without relying on