#include <iostream>
class Strategy
{
public:
virtual void execute() = 0;
};
class Strategy1 : public Strategy
{
public:
virtual void execute() override { std::cout << "executed1\n"; }
};
class Strategy2 : public Strategy
{
public:
virtual void execute() override { std::cout << "executed2\n"; }
};
template <typename S>
class StaticStrategy
{
S strategy;
public:
void execute()
{
strategy.execute();
}
};
class DynamicStrategy
{
Strategy* strategy;
public:
DynamicStrategy(Strategy* strategy) : strategy(strategy) {}
void execute()
{
strategy->execute();
}
void setStrategy(Strategy* newStrategy)
{
delete strategy;
strategy = newStrategy;
}
~DynamicStrategy()
{
delete strategy;
}
};
int main()
{
StaticStrategy<Strategy1> staticStrategy;
staticStrategy.execute();
DynamicStrategy dynamicStrategy(new Strategy1{});
dynamicStrategy.execute();
dynamicStrategy.setStrategy(new Strategy2{});
dynamicStrategy.execute();
}
Here is an example of the static and the dynamic strategy pattern written in c++. I wonder why would someone use a static strategy instead of a dynamic one. It seems like the dynamic one does all the job of the static one but also have more flexibility since the strategy can be changed at run time. Can anyone give me an example where a static strategy would be better that a dynamic one?
The static version is strictly more powerful and easier to use in some ways.
The static version only requires that S
have a member function execute
, whereas the dynamic version imposes upon the user inheritance from Strategy
.
The static version places no requirements on allocation strategy or lifetime, whereas in the snippet the dynamic version requires heap allocation. An alternative of the dynamic version is possible without allocation if it does not take ownership, in which case the client must be concerned with the Strategy
lifetime.
Given the static version, a client who wants heap allocation can erase the strategy type to have heap allocation with a single strategy type. But given the dynamic version above, a client cannot undo the requirement for heap allocation.
The static version is completely visible to the compiler and this information is available for optimization. The dynamic version indirects through the Strategy
base class, so inlining cannot occur unless the compiler can prove (or speculate) the concrete Strategy
class being used.