A mate put me on to the book Head First Design Patterns the other day, and it’s excellent, so I’ve been reading away and coding up the examples. The examples themselves are in Java, but I’m more interested in C++ so I’m transcoding them as I go (pun!).
The Strategy pattern aims to give separate implementations of algorithms (in other words – functions) to different subclasses of your major class, and allow you to change the behaviour at run-time, rather than have it hard-coded at compile-time. Pretty neat.
Now for the ducks…
/*
Pattern: Strategy
Definition: The strategy pattern defines a family of algorithms (i.e. functions), encapsulates each one, and
makes them interchangable. The Strategy pattern lets the algorithm vary independently from clients that use it.
Example source: Head-First Design Patterns, pages 13-24 [ Converted from Java to C++ | 10/07/2011 | r3dux ]
*/
#include <iostream>
using namespace std;
// ----------------------- Quack interface -------------------------
class QuackBehaviour
{
public:
virtual void quack() = 0; // Abstract class because of this pure virtual function
};
class Quack : public QuackBehaviour
{
public:
void quack()
{
cout << "The duck says: Quack!" << endl;
}
};
class MuteQuack : public QuackBehaviour
{
public:
void quack()
{
cout << "The duck says: <<< Silence >>>" << endl;
}
};
// ----------------------- End of Quack interface -------------------------
// ----------------------- Fly interface -------------------------
class FlyBehaviour
{
public:
virtual void fly() = 0; // Abstract class because of this pure virtual function
};
class FlyWithWings : public FlyBehaviour
{
public:
void fly()
{
cout << "The duck flies into the friendly skies!" << endl;
}
};
class FlyNoWay : public FlyBehaviour
{
public:
void fly()
{
cout << "I can't fly!" << endl;
}
};
class FlyWithRocket : public FlyBehaviour
{
public:
void fly()
{
cout << "The duck flies through the air using a rocket!" << endl;
}
};
// ----------------------- End of Fly interface -------------------------
// ----------------------- Duck class and subtypes -------------------------
class Duck
{
public:
QuackBehaviour *quackBehaviour;
FlyBehaviour *flyBehaviour;
void performQuack()
{
quackBehaviour->quack();
}
void setQuackBehaviour(QuackBehaviour *qb)
{
cout << "Changing quack behaviour..." << endl;
quackBehaviour = qb;
}
void performFly()
{
flyBehaviour->fly();
}
void setFlyBehaviour(FlyBehaviour *fb)
{
cout << "Changing fly behaviour..." << endl;
flyBehaviour = fb;
}
void floatAround()
{
cout << "The duck bobs peacefully on the surface of the water." << endl;
}
virtual void display() = 0; // Make this an abstract class by having a pure virtual function
};
class MallardDuck : public Duck
{
public:
MallardDuck()
{
quackBehaviour = new Quack();
flyBehaviour = new FlyWithWings();
}
void display()
{
cout << "I'm a real mallard duck!" << endl;
}
};
class RubberDuck : public Duck
{
public:
RubberDuck()
{
quackBehaviour = new MuteQuack();
flyBehaviour = new FlyNoWay();
}
void display()
{
cout << "I'm a rubber-ducky!" << endl;
}
};
class PaintedDuck : public Duck
{
public:
PaintedDuck()
{
quackBehaviour = new MuteQuack();
flyBehaviour = new FlyNoWay();
}
void display()
{
cout << "I'm a painted wooden duck!" << endl;
}
};
// ----------------------- End of Duck class and subtypes -------------------------
// ----------------------- The main event -------------------------
int main()
{
Duck *mallard = new MallardDuck();
mallard->display();
mallard->floatAround();
mallard->performFly();
mallard->performQuack();
cout << endl << endl;
Duck *rubber = new RubberDuck();
rubber->display();
rubber->floatAround();
rubber->performFly();
rubber->performQuack();
cout << endl << endl;
Duck *painted = new PaintedDuck();
painted->display();
painted->floatAround();
painted->performFly();
painted->setFlyBehaviour(new FlyWithRocket);
painted->performFly();
painted->performQuack();
painted->setQuackBehaviour(new Quack);
painted->performQuack();
return 0;
}
Which gives the output:
I’m a real mallard duck!
The duck bobs peacefully on the surface of the water.
The duck flies into the friendly skies!
The duck says: Quack!I’m a rubber-ducky!
The duck bobs peacefully on the surface of the water.
I can’t fly!
The duck says: <<< Silence >>>I’m a painted wooden duck!
The duck bobs peacefully on the surface of the water.
I can’t fly!
Changing fly behaviour…
The duck flies through the air using a rocket!
The duck says: <<< Silence >>>
Changing quack behaviour…
The duck says: Quack!
Update 24th Nov 2012: ijab points out in the comments below that this code contains memory leaks, and yup it does – so I’ve provided a version with the memory leaks fixed in my reply below, but have deliberately left the original version above to keep things focused. All you really need to do avoid leaking memory is:
– Have virtual destructors for the xxxBehaviour classes (they don’t have to do anything special, but they need to exist or the compiler will give you warnings),
– Delete the existing behaviour before creating and applying a new one (maybe only delete if they’re not null – you choose), and
– Don’t forget to delete your ducks at the end of the program!