An example implementation of the Strategy design pattern in C++

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…

  1. /*
  2. Pattern: Strategy
  3. Definition: The strategy pattern defines a family of algorithms (i.e. functions), encapsulates each one, and
  4. makes them interchangable. The Strategy pattern lets the algorithm vary independently from clients that use it.
  5. Example source: Head-First Design Patterns, pages 13-24 [ Converted from Java to C++ | 10/07/2011 | r3dux ]
  6. */
  7.  
  8. #include <iostream>
  9.  
  10. using namespace std;
  11.  
  12. // ----------------------- Quack interface -------------------------
  13. class QuackBehaviour
  14. {
  15. 	public:
  16. 		virtual void quack() = 0; // Abstract class because of this pure virtual function
  17. };
  18.  
  19. class Quack : public QuackBehaviour
  20. {
  21. 	public:
  22. 		void quack()
  23. 		{
  24. 			cout << "The duck says: Quack!" << endl;
  25. 		}
  26. };
  27.  
  28. class MuteQuack : public QuackBehaviour
  29. {
  30. 	public:
  31. 		void quack()
  32. 		{
  33. 			cout << "The duck says: <<< Silence >>>" << endl;
  34. 		}
  35. };
  36. // ----------------------- End of Quack interface -------------------------
  37.  
  38.  
  39. // ----------------------- Fly interface -------------------------
  40. class FlyBehaviour
  41. {
  42. 	public:
  43. 		virtual void fly() = 0; // Abstract class because of this pure virtual function
  44. };
  45.  
  46. class FlyWithWings : public FlyBehaviour
  47. {
  48. 	public:
  49. 		void fly()
  50. 		{
  51. 			cout << "The duck flies into the friendly skies!" << endl;
  52. 		}
  53. };
  54.  
  55. class FlyNoWay : public FlyBehaviour
  56. {
  57. 	public:
  58. 		void fly()
  59. 		{
  60. 			cout << "I can't fly!" << endl;
  61. 		}
  62. };
  63.  
  64. class FlyWithRocket : public FlyBehaviour
  65. {
  66. 	public:
  67. 		void fly()
  68. 		{
  69. 			cout << "The duck flies through the air using a rocket!" << endl;
  70. 		}
  71. };
  72. // ----------------------- End of Fly interface -------------------------
  73.  
  74. // ----------------------- Duck class and subtypes -------------------------
  75. class Duck
  76. {
  77. 	public:
  78. 		QuackBehaviour *quackBehaviour;
  79. 		FlyBehaviour   *flyBehaviour;
  80.  
  81. 		void performQuack()
  82. 		{
  83. 			quackBehaviour->quack();
  84. 		}
  85.  
  86. 		void setQuackBehaviour(QuackBehaviour *qb)
  87. 		{
  88. 			cout << "Changing quack behaviour..." << endl;
  89. 			quackBehaviour = qb;
  90. 		}
  91.  
  92. 		void performFly()
  93. 		{
  94. 			flyBehaviour->fly();
  95. 		}
  96.  
  97. 		void setFlyBehaviour(FlyBehaviour *fb)
  98. 		{
  99. 			cout << "Changing fly behaviour..." << endl;
  100. 			flyBehaviour = fb;
  101. 		}
  102.  
  103. 		void floatAround()
  104. 		{
  105. 			cout << "The duck bobs peacefully on the surface of the water." << endl;
  106. 		}
  107.  
  108. 		virtual void display() = 0; // Make this an abstract class by having a pure virtual function
  109.  
  110.  
  111. };
  112.  
  113. class MallardDuck : public Duck
  114. {
  115. 	public:
  116. 		MallardDuck()
  117. 		{
  118. 			quackBehaviour = new Quack();
  119. 			flyBehaviour   = new FlyWithWings();
  120. 		}
  121.  
  122. 		void display()
  123. 		{
  124. 			cout << "I'm a real mallard duck!" << endl;
  125. 		}
  126.  
  127. };
  128.  
  129. class RubberDuck : public Duck
  130. {
  131. 	public:
  132. 		RubberDuck()
  133. 		{
  134. 			quackBehaviour = new MuteQuack();
  135. 			flyBehaviour   = new FlyNoWay();
  136. 		}
  137.  
  138. 		void display()
  139. 		{
  140. 			cout << "I'm a rubber-ducky!" << endl;
  141. 		}
  142. };
  143.  
  144. class PaintedDuck : public Duck
  145. {
  146. 	public:
  147. 		PaintedDuck()
  148. 		{
  149. 			quackBehaviour = new MuteQuack();
  150. 			flyBehaviour   = new FlyNoWay();
  151. 		}
  152.  
  153. 		void display()
  154. 		{
  155. 			cout << "I'm a painted wooden duck!" << endl;
  156. 		}
  157. };
  158. // ----------------------- End of Duck class and subtypes -------------------------
  159.  
  160. // ----------------------- The main event -------------------------
  161. int main()
  162. {
  163. 	Duck *mallard = new MallardDuck();
  164. 	mallard->display();
  165. 	mallard->floatAround();
  166. 	mallard->performFly();
  167. 	mallard->performQuack();
  168.  
  169. 	cout << endl << endl;
  170.  
  171. 	Duck *rubber = new RubberDuck();
  172. 	rubber->display();
  173. 	rubber->floatAround();
  174. 	rubber->performFly();
  175. 	rubber->performQuack();
  176.  
  177. 	cout << endl << endl;
  178.  
  179. 	Duck *painted = new PaintedDuck();
  180. 	painted->display();
  181. 	painted->floatAround();
  182. 	painted->performFly();
  183. 	painted->setFlyBehaviour(new FlyWithRocket);
  184. 	painted->performFly();
  185. 	painted->performQuack();
  186. 	painted->setQuackBehaviour(new Quack);
  187. 	painted->performQuack();
  188.  
  189. 	return 0;
  190. }

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!