11

I want to ask something about duck example on this book that made me confused and I feel contradictions.

  1. Problem enter image description here

  2. the conclusions enter image description here

He said "when joe added new behavior to the duck superclass, he was also adding behavior that was not appropiate for sume Duck subclasses"

BUT in the conclusion he added performFly() and performQuack(); what is the different because i think it same with he was also adding behavior that was not appropiate for sume Duck subclasses?

**image taken from the book Head first design pattern ** this question doesn't state this book is not good, this book is really good in my opinion. this is just me who is asking something that I didn't get from the book.

Kakashi
  • 3,329
  • 4
  • 26
  • 37
  • 2
    All they did was take a function (quack) and separate it to a separate class. That is a bit complicated. It would be better to make a subclass of ducks called "FlyingDucks" and then put Fly() in there. Then, all flying ducks will inherit that class. Alternately, made FLy() abstract, forcing every subclass to define what it means to fly. What they did was more work and more complicated. Every subclass needs to pick a Fly class to assign to flyBehavior - even if they cannot fly. – kainaw Jan 11 '15 at 13:44
  • 1
    Am I right if i say `the problem` and `the conclusion` is contradiction? or i just dont get it what he means? – Kakashi Jan 11 '15 at 13:53
  • 1
    It would be better design to realize that, the way the (made-up) problem is considering ducks, a rubber duck is not a duck -- it doesn't fly, it doesn't swim (unless you include floating), etc. If, for some reason, you really wanted to have a class that encompassed real ducks and rubber ducks, then you should look for commonalities in these items your problem space, and make those the common attributes; not start with attributes common to some of the items in your space and force-fit the others to it. – arcy Jan 11 '15 at 13:54
  • 1
    One thing to note, this is the first chapter of the book and several concepts they could have used for this solution had not yet been introduced. A lot of times they state that 'it might be done a better way and they will address this later.' (paraphrase) – Todd Vance Dec 21 '16 at 18:07

4 Answers4

8

I'm not a guru of design patterns, but while I was reading that book, the first feeling I had about that particular chapter was that the way interfaces was built and then implemented, violated one of the well know programming principle: the Interface Segregation Principle (ISP) Basically this principle state that

no client should be forced to depend on methods it does not use

Because some Ducks that don't fly implement the fly() method even it they don't need it. That said, I think that in this particular case it is unavoidable to implement all the interfaces methods since on the client side we're using polymorphic behaviors, and we need to be sure that we have all the methods available even if unused.

Antonio Pantano
  • 4,592
  • 2
  • 23
  • 26
5

The strategy pattern works when you favor composition over inheritance http://en.wikipedia.org/wiki/Composition_over_inheritance

This is a good practice because you can change the behavior of a class without having to change any code. And you don't need a huge tree of classes either. You also can change the behavior of a class dynamically.

What it does in the example is that defines "behaviors" in the parent class. In the parent class you define that a Duck can have a flying behavior and a quacking behavior. But it doesn't mean the children classes have to have quack or fly.

You can have a nonflying duck and when you call "fly" it will do nothing because we'll have a "non-flying" behavior.

Instead of hardcoding what a duck does in the class, you can change the behavior of this duck whenever you want.

aimme
  • 6,385
  • 7
  • 48
  • 65
pearpages
  • 18,703
  • 1
  • 26
  • 27
2

In the conclusion, he is adding two new classes that have a fly() function. However, the function does not always make the duck fly. Rubber ducks can't fly, so they use an instance of the FlyNoWay class. Other ducks that can fly use an instance of the FlyWithWings class. The field flyBehavior in the Duck class would probably be set in the constructor.

The function performFly() would call the fly() function for whatever class is chosen.

As stated by kainaw in the comments, this is a rather complicated solution. However, it can still be used. Say that you are creating a duck designing program. If the user chooses whether the duck can fly, it can't be hard coded. You could create a Boolean value, but you might need to handle more complicated situations like behavior. You might need a WildDuckBehavior class and a DomesticDuckBehavior, each with its own information about how to act. Basically, the example in the book is a simplified version of how this would be used.

James Westman
  • 2,680
  • 1
  • 15
  • 20
2

You're correct. The solution offered by the book suffers from one huge problem: "FlyNoWay" is not a sub case of "FlyBehaviour". To have any meaning, FlyBehaviour must require the ability to fly. Classes that inherit from it will specify the behaviour (fly using wings etc.). A sub class cannot contain less than the class it inherits from.

Taking a closer look, "FlyNoWay" is just a pseudo class that was introduced to solve the problem of polymorphism in an inappropriate way.

The right method is to use interfaces.

class Duck
{
    swim();
}

class MallardDuck : IFlyable
{
    fly();
}

class RedheadDuck : IFlyable, IQuackable
{
    fly();
    quack();
}

What about code reuse? Well you have to make the interface as strict as possible, assuring that most changes in the interface will cause the program to not compile.

AGuyCalledGerald
  • 7,882
  • 17
  • 73
  • 120