我喜欢在C ++中实现策略模式的最佳方式。到目前为止,我一直使用标准方式,其中上下文具有指向基本策略类的指针,如下所示:
class AbstractStrategy{
public:
virtual void exec() = 0;
}
class ConcreteStrategyA{
public:
void exec();
}
class ConcreteStrategyB{
public:
void exec();
}
class Context{
public:
Context(AbstractStrategy* strategy):strategy_(strategy){}
~Context(){
delete strategy;
}
void run(){
strategy->exec();
}
private:
AbstractStrategy* strategy_;
由于指向对象的指针可能导致不良行为,我一直在寻找一种更安全的方式来实现这种模式,我发现this question提出了std::function
作为处理这种模式的更好方法。
有人可以更好地解释一下std::function
的工作原理,也许还有战略模式的例子吗?
答案 0 :(得分:10)
请注意,单方法对象与函数同构,策略只是单方法对象。
所以基本上,你摆脱了所有的课程,而你只需使用std::function<void()>
:
class Context {
public:
template<typename F>
explicit Context(F strategy) : strategy(std::move(strategy)) { }
void run() { strategy(); }
private:
std::function<void()> strategy;
};
然后你可以将任何callable传递给Context
的构造函数:
Context ctx([] { std::cout << "Hello, world!\n"; });
ctx.run();
答案 1 :(得分:4)
对此主题here和here进行了一些讨论。我认为这取决于手头的具体情况。例如,你的策略只是一个简单的函数调用 - 我经常有策略模式,我的策略需要多种功能,只需要一个函数或函数就不能很好地处理。但是如果你确实只需要一个函数或函子,那么std::function
是一种方便的方法,可以实现最大的灵活性,存储函数指针,lambdas或functor。可能存在性能问题,对于原始的boost实现,已经讨论了here。
答案 2 :(得分:1)
研究райтфолд
的答案基本上,你摆脱了所有的类,你只需使用std :: function。
这个通用函数允许你传递函数,lambda,仿函数和成员函数(使用std :: bind)
class Context {
public:
explicit Context(std::function<void()> input) : strategy(input) { }
void run() { strategy(); }
private:
std::function<void()> strategy;
};
然后你可以将任何callable传递给Context的构造函数:
Context ctx([] { std::cout << "Hello, world!\n"; });
ctx.run();
或
void sayHelloWorld(){
std::cout << "Hello, world!\n";
}
int main(){
Context ctx( sayHelloWorld );
ctx.run();
}
或
class SayHelloWorld{
operator()(){std::cout << "Hello, world!\n";}
}
int main(){
SayHelloWorld hello_world;
Context ctx( hello_world );
ctx.run();
}
答案 3 :(得分:0)
这样的东西?
#include <functional>
#include <iostream>
typedef std::function<int(int)> Strategy;
void execute_strategy(Strategy strategy, int object) {
std::cout << strategy(object) << std::endl;
};
int power2(int i) {
return i*i;
};
int main() {
execute_strategy(power2, 3);
}
我的意思是,策略模式是解决没有实际lambda的缺点。这已经解决了,所以你可以通过相应的函数。