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!

13 thoughts on “An example implementation of the Strategy design pattern in C++”

  1. Nicely done.

    Don’t know if you’ve already linked this, but a good condensed explanatory resource can be seen here.

    It’s got semantic class structures as well as example class structure diagrams, yo!

    1. Thanks, man. Nope – hadn’t seen that page before, looks like a great resource, and the semantic class structures are tiiiiiiiiiight! =P

  2. Memory leak in your codes. You new Behanvior objects in two Duck’s children class constructor, but not release them.

    MallardDuck()
    {
    quackBehaviour = new Quack();
    flyBehaviour = new FlyWithWings();
    }

    and

    RubberDuck()
    {
    quackBehaviour = new MuteQuack();
    flyBehaviour = new FlyNoWay();
    }

    1. Yup, you’re absolutely right. Running valgrind on the code as it stands gives:

      Memcheck, a memory error detector
      Copyright (C) 2002-2011, and GNU GPL’d, by Julian Seward et al.
      Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
      Command: ./5\ -\ Programming\ to\ an\ Interface

      HEAP SUMMARY:
      in use at exit: 136 bytes in 11 blocks
      total heap usage: 11 allocs, 0 frees, 136 bytes allocated

      LEAK SUMMARY:
      definitely lost: 88 bytes in 5 blocks
      indirectly lost: 48 bytes in 6 blocks
      possibly lost: 0 bytes in 0 blocks
      still reachable: 0 bytes in 0 blocks
      suppressed: 0 bytes in 0 blocks
      Rerun with –leak-check=full to see details of leaked memory

      This is both because we’re not deleting any existing behaviours before creating new ones, and because we don’t delete the ducks at the end.

      So to fix this, we could use code like this (changes are marked in comments with NEW tag):

      /*
      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 ]
       
      Updated 24/11/2012 to remove memory leaks
      */
       
      #include <iostream>
       
      using namespace std;
       
      // ----------------------- Quack interface -------------------------
      class QuackBehaviour
      {
      	public:
      		virtual void quack() = 0; // Abstract class because of this pure virtual function
       
      	        // NEW: virtual QuackBehaviour destructor
      		virtual ~QuackBehaviour()
      		{
      	            cout << "In QuackBehaviour destructor!" << endl;
      	        }
      };
       
      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
       
      	        // NEW: virtual FlyBehaviour destructor
      		virtual ~FlyBehaviour()
      		{
      	            cout << "In FlyHBehaviour destructor!" << endl;
      	        }
      };
       
      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;
      			delete quackBehaviour; // NEW: Delete existing quack behaviour before assigning new behaviour
      			quackBehaviour = qb;
      		}
       
      		void performFly()
      		{
      			flyBehaviour->fly();
      		}
       
      		void setFlyBehaviour(FlyBehaviour *fb)
      		{
      			cout << "Changing fly behaviour..." << endl;
      			delete flyBehaviour; // NEW: Delete existing fly behaviour before assigning new behaviour
      			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
       
      		// NEW: Provide a destructor to free the memory used by our behaviours
      		virtual ~Duck()
      		{
      			cout << endl << "In Duck destructor deleting quack and fly behaviours..." << endl;
      			delete quackBehaviour;
      			delete flyBehaviour;
      		}
       
      };
       
      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();
       
      	cout << endl << endl;
       
      	// NEW: Free the memory used by our ducks
      	delete mallard;
      	delete rubber;
      	delete painted;
       
      	return 0;
      }

      Running valgrind on that gives:

      Memcheck, a memory error detector
      Copyright (C) 2002-2011, and GNU GPL’d, by Julian Seward et al.
      Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
      Command: ./5\ -\ Programming\ to\ an\ Interface

      HEAP SUMMARY:
      in use at exit: 0 bytes in 0 blocks
      total heap usage: 11 allocs, 11 frees, 136 bytes allocated

      All heap blocks were freed — no leaks are possible

      I think that’s the correct way to eliminate the memory leaks, and there’s no compiler warnings about undefined behavior or anything – let me know if you’ve got a better way!

      Cheers!

    1. Glad you found it of use!

      And yes, I think you’re right – as we have a destructor we should probably have overloaded copy and assignment operators as well so that we can perform ‘deep copies’ of objects. However, in this example we don’t actually perform any assignment of one Duck object to another, or any duplication of Duck objects, so I didn’t provide these overloaded methods to keep things clean.

      I’m always interested in coding principles like this so if you find any other related / interesting things in your travels I’d love to hear about ’em =D

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.