如何使用 std::function 在 C++ 中实现策略模式
How to implement strategy pattern in C++ with std::function
我正在讨论在 C++ 中实现策略模式的最佳方式。到目前为止,我一直使用标准方式,其中上下文有一个指向基本策略 class 的指针,如下所示:
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_;
由于指向对象的指针会导致不良行为,我一直在寻找一种更安全的方法来实现此模式,我发现 其中 std::function
被提议作为处理此问题的更好方法模式。
有人可以更好地解释 std::function
的工作原理吗,也许可以举个策略模式的例子?
请注意,单一方法对象与函数同构,策略只是单一方法对象。
所以基本上,您摆脱了所有 类,而只使用 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;
};
然后你可以将任何可调用对象传递给Context
的构造函数:
Context ctx([] { std::cout << "Hello, world!\n"; });
ctx.run();
是这样的吗?
#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 的缺点的解决方案。这已经解决了,所以你可以传递适当的功能。
有一些关于这个主题的讨论 here and here. I think it depends on the particular case at hand. Is your strategy a simple function call only, for instance - I often have strategy patterns in which my strategy will need multiple capabilities, which isn't handled well by just having a function or functor. But if you do need just a function or functor, then std::function
is a handy way to allow ultimate flexibility, storing function pointers, lambdas or functors. There can be performance issues, which were discussed here 对于原始的 boost 实现。
正在研究 райтфолд 的答案
基本上,您摆脱了所有 类,而只使用 std::function。
此通用函数允许您传递函数、lambda、仿函数和成员函数(使用 std::bind)
class Context {
public:
explicit Context(std::function<void()> input) : strategy(input) { }
void run() { strategy(); }
private:
std::function<void()> strategy;
};
然后你可以将任何可调用对象传递给 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();
}
我正在讨论在 C++ 中实现策略模式的最佳方式。到目前为止,我一直使用标准方式,其中上下文有一个指向基本策略 class 的指针,如下所示:
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_;
由于指向对象的指针会导致不良行为,我一直在寻找一种更安全的方法来实现此模式,我发现 std::function
被提议作为处理此问题的更好方法模式。
有人可以更好地解释 std::function
的工作原理吗,也许可以举个策略模式的例子?
请注意,单一方法对象与函数同构,策略只是单一方法对象。
所以基本上,您摆脱了所有 类,而只使用 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;
};
然后你可以将任何可调用对象传递给Context
的构造函数:
Context ctx([] { std::cout << "Hello, world!\n"; });
ctx.run();
是这样的吗?
#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 的缺点的解决方案。这已经解决了,所以你可以传递适当的功能。
有一些关于这个主题的讨论 here and here. I think it depends on the particular case at hand. Is your strategy a simple function call only, for instance - I often have strategy patterns in which my strategy will need multiple capabilities, which isn't handled well by just having a function or functor. But if you do need just a function or functor, then std::function
is a handy way to allow ultimate flexibility, storing function pointers, lambdas or functors. There can be performance issues, which were discussed here 对于原始的 boost 实现。
正在研究 райтфолд 的答案
基本上,您摆脱了所有 类,而只使用 std::function。
此通用函数允许您传递函数、lambda、仿函数和成员函数(使用 std::bind)
class Context {
public:
explicit Context(std::function<void()> input) : strategy(input) { }
void run() { strategy(); }
private:
std::function<void()> strategy;
};
然后你可以将任何可调用对象传递给 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();
}