25

In the past, I have seen the strategy pattern explained as a mechanism which allows the user of a function/class to provide their own functionality for that function/class.

I had always been taught that the way to implement the pattern was by taking function pointers into your classes/functions and calling them internally, thus allowing the programmer to provide their own "strategy" which would be used internally by those functions and objects.

Looking around more recently, I see that the strategy pattern always seems to be explained/defined through the use of an inheritance hierarchy like so:

Strategy pattern implementation

is this a difference of opinion/implementation, or is the function pointer passing not really a variation of the strategy pattern? I'm mostly interested so I don't confuse people when I comment or explain my code :)

Lazer
  • 90,700
  • 113
  • 281
  • 364
John Humphreys
  • 37,047
  • 37
  • 155
  • 255
  • 7
    Someone just downvoted the question and both answers with no comments... I hate people sometimes :p – John Humphreys Sep 06 '11 at 18:39
  • 5
    Yeah. I flagged the question, we'll see if a mod will come and fix it. – Ernest Friedman-Hill Sep 06 '11 at 18:40
  • 2
    There's no irregular voting patterns here. From the flags I'm fully convinced that someone flew by and just started clicking down vote. As this is a rare example of 'good subjective' (IMHO) and I do work with C++ (at least enough to understand the question), I'm inclined to click up vote a few times. Please flag if this happens again and I'll ask a dev to look into it. – Tim Post Sep 06 '11 at 18:56
  • Thanks guys, very enlightening answers :) – John Humphreys Sep 06 '11 at 19:16

6 Answers6

23

You simply have to use inheritance in languages without function pointers (read: Java).

Personally, I would prefer std::function over raw function pointers, because it accepts a wider range of arguments and allows you to maintain state in the strategy object.

Also, if you already know the strategy at compile-time, you can even use templates and thus save both the space and runtime overhead of function pointers and std::function objects.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • 1
    Or: you have to use function pointers in languages without objects! – Ernest Friedman-Hill Sep 06 '11 at 18:35
  • 3
    @Ernest: And as always, C++ gives you a choice. I was just laying out the possibilities, so w00te can make an informed choice. Unfortunately, some Design Patterns officionado didn't agree and immediately voted me down. – fredoverflow Sep 06 '11 at 18:40
  • Looks like he voted down the question and all three answers simultaneously -- I've called in a moderator. – Ernest Friedman-Hill Sep 06 '11 at 18:41
  • 5
    The choice of `std::function` against bare function pointers points out that strategy objects can have *state*. This is the real point in using interfaces: strategy objects can maintain variables, function pointers cannot. – Alexandre C. Sep 06 '11 at 18:45
  • Would providing a functor/function-object as a parameter be a suitable replacement for the inheritance heirarchy then? That could have state :) – John Humphreys Sep 06 '11 at 18:47
18

In my opinion, implementation of strategy pattern using function pointers is done in languages which don't have support for OOP (such as C).

In languages which support OOP, its better implemented using classes : inheritance, virtual functions (i.e runtime polymorphism), interface, and so on. Usually, this is runtime strategy pattern which means, you can change the behavior of the program just by switching to other strategy pattern, at runtime.

In C++, there is also a compile-time strategy pattern, commonly known as policy-based design.

In any case, classes can maintain states, while function pointers cannot. That is the biggest advantage in using classes.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
9

Using function pointers to implement strategy is sort of a degenerate case of the inheritance based version. The essential kernel of the pattern is, as you know, being able to supply or modify a component of some process at runtime. That component can be a function, or it can be an object. If the strategy consists of several bits, an inheritance-based version is really nicer, as an object can package several methods together; if there's just one piece, then function pointers are pretty much as good.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
2

IMO, starategy pattern can be implemented using:

  • Templates and compile-time constant expressions (Early-bound, may not be actually called as strategy-pattern).
  • Virtual function mechanism (Yes, by assigning different derived classes to a reference/pointer).
  • Function pointers
  • Pointer-to-members (methods) of a class.
  • Using std::function, and using lambdas.
Ajay
  • 18,086
  • 12
  • 59
  • 105
2

Interface objects can have state, and therefore maintain member variables. Function pointers cannot.

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
0

This is a practical code for strategy pattern in c++. I hope pure virtual funcation usage (instead of interface in Java) is self explanatory.

#include <iostream>
#include <fstream>
#include <string.h>

using namespace std;

class Strategy;

class TestBed{
  public:
    TestBed(){
        myStrategy = NULL;
    }
    void setBehavior(int type);
    Strategy *myStrategy;
};

class Strategy{
  public:
    void performBehavior(){
       behave();
    }
  private:
    virtual void behave() = 0;
};

class behaviorOne: public Strategy{
  private:
    void behave(){
        cout << "left strategy" << endl;
    }
};

class behaviorTwo: public Strategy{
  private:
    void behave(){
        cout << "right strategy" << endl;
    }
};

class behaviorThree: public Strategy{
  private:
    void behave(){
        cout << "center strategy" << endl;
    }
};

void TestBed::setBehavior(int type){  
  delete myStrategy;
  if (type == 0)
    myStrategy = new behaviorOne();
  else if (type == 1)
    myStrategy = new behaviorTwo();
  else if (type == 2)
    myStrategy = new behaviorThree();
}

int main(){
  TestBed test;
  int answer;  
  while(1){
     cout << "Exit(other) Left(0) Right(1) Center(2): ";
     cin >> answer;
     if(answer > 2) break;
     test.setBehavior(answer);
     test.myStrategy->performBehavior();
  }   
  return 0;
}
mehmet riza oz
  • 541
  • 6
  • 18