I am strongly in favor of the strategy outlined in the answer by @DocBrown.
I am going to suggest an improvement to the answer.
The calls
myMap.Add(1,new Strategy1());
myMap.Add(2,new Strategy2());
myMap.Add(3,new Strategy3());
can be distributed. You don't have to go back to the same file to add another strategy, which adheres to the Open-Closed principle even better.
Say you implement Strategy1
in file Strategy1.cpp. You can have the following block of code in it.
namespace Strategy1_Impl
{
struct Initializer
{
Initializer()
{
getMap().Add(1, new Strategy1());
}
};
}
using namespace Strategy1_Impl;
static Initializer initializer;
You can repeat the same code in every StategyN.cpp file. As you can see, that will be a lot of repeated code. To reduce the code duplication, you can use a template which can be put in a file that is accessible to all the Strategy
classes.
namespace StrategyHelper
{
template <int N, typename StrategyType> struct Initializer
{
Initializer()
{
getMap().Add(N, new StrategyType());
}
};
}
After that, the only thing you have to use in Strategy1.cpp is:
static StrategyHelper::Initializer<1, Strategy1> initializer;
The corresponding line in StrategyN.cpp is:
static StrategyHelper::Initializer<N, StrategyN> initializer;
You can take the use of templates to another level by using a class template for the concrete Strategy classes.
class Strategy { ... };
template <int N> class ConcreteStrategy;
And then, instead of Strategy1
, use ConcreteStrategy<1>
.
template <> class ConcreteStrategy<1> : public Strategy { ... };
Change the helper class to register Strategy
s to:
namespace StrategyHelper
{
template <int N> struct Initializer
{
Initializer()
{
getMap().Add(N, new ConcreteStrategy<N>());
}
};
}
Change the code in Strateg1.cpp to:
static StrategyHelper::Initializer<1> initializer;
Change the code in StrategN.cpp to:
static StrategyHelper::Initializer<N> initializer;