Let's say I have an abstract class bird, and one of its functions is fly(int height).
I have numerous different bird classes, each with it's own different implementation of fly, and the function is used extensively across the application.
One day my boss comes and demands I add a duck, which does everything the other birds do except that it doesn't fly but rather swims in the application's pond.
Adding the duck as sub-type of bird violates Liskov substitution rule because when calling duck.fly we would either throw an exception, do nothing, or violate the correctness principle.
How would you go about introducing this change while keeping in mind the SOLID design principles?
I see 3 options for you:
Use
Bird
as an abstract base class for the common functionality and derive from itFlyingBird
andAquaticBird
.Use object composition and visitor pattern as described by Zoran Horvat: https://vimeo.com/195774910 (which is worthwhile to watch in any case) - Although, it seems an overkill in the case at hand.
Use the solution as you have described it.
At the end, It's all about the balance. If you're expecting many different birds with different abilities to join in, then you should seriously consider option 2, otherwise depending on how you use the classes later choose between 1 and 3.
Update as per Gilads comments about Option 2 (Object Composition & Visitor Pattern)
The main thing here is that you can have one class
Bird
and attach Abilities to it such asFlying
andSwimming
and maybe later on you decide that you have other abilities or classification of some kind. You can do it either by creating different interfaces (IFlyable
,ISwimmable
) and have something like this:And then use the visitor pattern to visit the specific actions.
Or, if you look for something more robust and elegant you could Create different classes per Ability and attach them to the Bird class:
You could later have some static class to create the birds:
The Ability and Swim can look like this:
I Have not attached the full code as it's not mine and it's way too long for this answer. I say again that this looks like an overkill for the case you described.
I strongly advise you to watch the video from Zoran Horvat and download and play with the code he provides: http://www.postsharp.net/blog/post/webinar-recording-object-composition