all ducks can swim and quack(),
the ducks override the display() method to draw something on the screen
New requirement is to add fly capability to the duck.
this will create an issue, as we added fly() to the Duck class, it means that all sub classes will inherit this behavior, but some ducks cannot fly like RubberDuck
you may say it is easy to fix this issue, simply override the fly() method in the RubberDuck class
ok this is good, but you have to do that for all sub classes similar to RubberDuck, and in the future if you add a new class like WoodenDuck, you should override it again
you may think of a different solution, as the fly() method is making trouble in Duck class, lets take it out of this class, and put it in an Interface, and let everyone subclass implement this interface (same for quack() method, as also not all ducks quack)
but now you should implement fly() in each subclass, eventhough some subclasses share the same flying behaviour
this will lead us to the first design principle identify the aspects of your application that vary and separate them from what stays the same
so in our case we have 2 aspects the flying and quacking, we will take them out of the Duck class but not like the way we did in the previous image,
we will define an interface which is FlyBehaviour, and we will define some classes that implement this interface and define some flying behavior
now the Duck class will have an Instance of FlyBehaviour and QuackBehavior
as you can see we defined a method performQuack() which calls the quack() method.
the full picture will be like this, and this is the Strategy Pattern we separate the behavior that change a alot.
what is nice in this implementation that you can change the behavior of the class at run time, so you can start by fly behavior and change it later.
as you can see we used setFlyBehavoir to change the fly behaviour at run time
Always Encapsulate what varies
Always prefer composition over inheritance, with inheritance you are stucked with the inherited class, with composition you can attach yourself to any class you want, in addition composition allows you to change the class at runtime.
Program to Interface not Implementation so you can get benefit of polyomorphism