0

So I have started learning book called head first design pattern and in its initial chapter it has given a scenario where composition is preferred over inharitance with a duck class example.

public abstract class Duck
{
   Swim()
       { 
          //all ducks can swim same way
       }
   abstract Look();// ducks can look different
}

So above duck class inherited by different types of ducks and also by some fake rubber duck.

(Based on duck type)

      Duck obj=new IndoDuck();
         //Or
     //Duck obj =new MallardDuck();

     obj.Swim();
     obj.Look();

So till now it looks good.

Now the change come to add a Flying behaviour to the ducks.

We cant just add fly method behaviour to the abstract duck class as there are fake ducks availbe who cant fly.

So author create a IFly interface which will be implemented by Flyable class and NonFlyable class.

interface IFly
{
 Fly();
}

Flyable: IFly
{
 Fly()
{
  // can fly
}
}

NonFlyable:IFly
{
 Fly()
{
  // cant fly
}
}

So this IFly interface will not be implemented by all the different ducks class as this will be a massive change to add flyable/non flyable behaviour to these ducks. So inharitance seems not a good idea here agree.

Author suggests IFly interface will be used inside the Duck class as composition.

public abstract class Duck
{
   Swim()
       { 
          //all ducks can swim same way
       }
   abstract Look();// ducks can look different

IFly Fly();
}

So now what i can do is.

      Duck obj=new IndoDuck();
         //Or
     //Duck obj =new MallardDuck();

     obj.Swim();
     obj.Look();
obj.Fly =new Flyable();
//or
obj.Fly=new NonFlyable();

so my questionis how would i know based on type if Flyable functionality to add or NonFlyable as somewhere i have to tell my each and every duck class that either they fly or they not right?? So how does composition actually solving the problem here i cant relate or i missed something?? Please help.

BishtDev
  • 33
  • 1
  • 1
  • 8

1 Answers1

0

so my questionis how would i know based on type if Flyable functionality to add or NonFlyable as somewhere i have to tell my each and every duck class that either they fly or they not

The code that makes the decision about which IFly subclass to create a duck with will usually reside in what is known as a Factory class. A straightforward and simple implementation of such a Factory class would look something like :

public class DuckFactory {
    public static Duck createDuck(DuckType type) {
         if(DuckType.FlyableMallard.equals(type)) {
              return new MallardDuck();
         } else if(DuckType.Mallard.equals(type)) {
              return new MallardDuck(new NonFlyable());
         }
    }
}

Note that the Duck sub-classes should have a constructor that takes a Flyable argument rather than setting it using obj.Fly = Flyable. To achieve this, you can add these constructors to the Duck class itself :

 public abstract class Duck {
       protected IFly flyBehavior;
       public AbstractDuck(IFly flyBehavior) {
            this.flyBehavior = flyBehavior;
       }

       public AbstractDuck() {
            //all ducks can fly by default
            this.flyBehavior = new Flyable();
       }

       protected abstract void look();
       //other methods
 }

Each of the duck sub-classes can then extend from AbstractDuck and inherit the constructors automatically. A simple main program can then create a Duck instance by simply passing the type received from the command line :

DuckType duckType = [duck type recieved as program input]
Duck duck  = DuckFactory.create(duckType);

So how does composition actually solving the problem

It should be clear from the above example that with composition, you are able to use a single class called MallardDuck and add Flyable or NonFlyable behavior without having to make the behavior mandatory for the Duck sub classes to override.

Chetan Kinger
  • 15,069
  • 6
  • 45
  • 82
  • 1
    your Duck Factory createDuck method violates Open Closed Principal. While we are talking about Design patterns it is certainly not recomended to do that. Replace it with Poly. – aspxsushil Oct 19 '19 at 17:54
  • @aspxsushil Quite the opposite actually. It adheres to the Open-Closed principle since the `Duck` implementations are open to extension but closed to modification. Take for example how the `MallardDuck` can became `Flyable` or `NonFlyable` without changing a single line of code in the `MallardDuck` class. Can you elaborate on what is your understanding of the open-closed principle and why you think otherwise? – Chetan Kinger Oct 19 '19 at 17:55
  • Thanks for your answer however by introducing simple factory i have to initialize all the duck class inside factory this i can accept (but it will initially change code at client calling) but by attaching flyable behaviour in constructor to each subclass will end up modifying/adding constructor for each subclass which again losing why we used composition over Inheritance as if at last i have to do any change in my class then what is the need to switch to composition?? – BishtDev Oct 19 '19 at 18:05
  • @jinnybat See my edit. You don't have to add a constructor to each subclass. You only need to add the constructor to the `Duck` class which will be inherited by all sub-classes. That said, your understanding of what it means to "change a class" seems a bit skewed. Modifying a class to add a constructor is OK. Modifying a class to change some behavior is the issue. With composition, you can change the behavior of a class without changing it's code (For example,, `MallardDuck` can fly or not fly just by changing the `Flyable` object passed to it). – Chetan Kinger Oct 19 '19 at 19:17
  • Yes it may be skewed, keeping in mind i am in learning phase of this however things are getting in place with the help of you guys. I am accepting this as an answer and thanks for such a wonderful example. – BishtDev Oct 20 '19 at 10:03
  • `DuckFactory` violates the OCP (rather than the implementations). The `static` method is closed to extension while the `if-else` chain is open to modification. – jaco0646 Oct 21 '19 at 15:02
  • @jaco0646 A few points to understand. 1) This is example code and not production code 2) Sometimes, one principle wins over another. In this case, KISS wins over OCP (Refactor code when you do see a design problem). 3) How would you achieve OCP for the `Duck` implementations and at the same time, create a component that doesn't use some sort of decision making to decide how to wire `Duck` objects? 4. The OP asked a very specific question which has been answered. Feel free to post an answer that adheres to **every rule in the book**. – Chetan Kinger Oct 21 '19 at 15:49