Wednesday, October 3, 2007

Strategy pattern (1)

My first post will talk about design patterns which you will mostly find people ask you about design patterns in your job interviews. Recently, I read a book called "Head First Design Patterns". I found it is a very fun book to read, so I decided to post reading notes for each pattern I read. Here we go, the first pattern - Strategy pattern:

1) Start with a case

We start with a case, say we've got a super class called "Duck" from which all other duck types inherit. We've also got subclasses such as MallardDuck, WoodenDuck and RubberDuck etc.

2) Problem we have

Now assume there are already some common methods that all the ducks share such as display(). Now here comes the problem, if we want to implement a fly() method for only some of the duck types (e.g. MallardDuck), how do we implement this?

3) Using inheritance

We can put the fly() method in the Duck class, but RubberDuck cannot fly. No problem, we can override the fly() method to do nothing in RubberDuck.

These are the disadvantages of using inheritance to provide Duck behavior:

  • Duplicate code ==> if we want to add a quack() method in the Duck class, since WoodenDuck cannot fly and quack, it has to override all these useless methods.
  • Changes affect others ==> if we want to add a quack() method in the Duck class, for every duck subclasses, we have to override it and let it do nothing.

4) How about interface?
we can create interfaces called "IFlyable" and "IQuackable", so only ducks that are supposed to fly will implement the IFlyable interface.

There are the disadvantages of using interface to provide Duck behavior:

  • Duplicate code ==> since interfaces have no implementation code, so no code reuse.
  • Changes affect others ==> there might be more than one kind of flying behavior even among the ducks that do fly, e.g. FlyWithWings, FlyNoWay, you want to change the flyable behavior, you need to change all the subclasses accordingly.

5) Design Principle
Now we've come to the point where we need a pattern to solve this problem. Before we start looking at the pattern, we need to understand our first of many design principles here:

Design Principle 1: Identify the aspects of your application that vary and separate them from what stays the same.

Here's another way to think about this principle: take the parts that vary and encapsulate them, so that later you can alter or extend the parts that vary without affecting those that don't. We know that fly() and quack() are the parts of the Duck class that vary across ducks. To separate these behaviors from the Duck class, we'll pull both methods out of the Duck class and create a new set of classes to represent each behavior.

6) Designing the Duck Behaviors

To be continued...

blog comments powered by Disqus