C ++中策略设计模式的模板和函数指针之间有什么区别
What are the differences between a template and a function pointer for a Strategy design pattern in C++
我正在用 C++ 实现一个策略设计模式,我发现了几个我可以采用的不同选项。一种方法是使用模板,可能如下所示:
namespace Strategies
{
struct IsEven
{
bool doSomething(int x) { return x % 2 == 0; }
};
struct IsOdd
{
bool doSomething(int y) { return y % 2 == 1; }
};
}
template<typename Strategy>
class Processor
{
public:
Processor() : _strat{ Strategy() }
{}
bool process(int num)
{
return _strat.doSomething(num);
}
private:
Strategy _strat;
};
int main()
{
Processor<Strategies::IsEven> templateOne{};
Processor<Strategies::IsOdd> templateTwo{};
std::cout << "Process 4 with One: " << (templateOne.process(4) ? "True" : "False") << std::endl;
std::cout << "Process 4 with Two: " << (templateTwo.process(4) ? "True" : "False") << std::endl;
}
另一种方法是使用函数指针,可能如下所示:
#include <functional>
class ProcessorTwo
{
public:
using StrategyFunction = std::function<bool(int)>;
static bool lessThanFive(int num) {
return num < 5;
}
static bool greaterThanFive(int num) {
return num > 5;
}
ProcessorTwo(StrategyFunction strat) : _strat{ strat }
{}
bool process(int num) {
return _strat(num);
}
private:
StrategyFunction _strat;
};
int main()
{
ProcessorTwo functionPointerOne{ ProcessorTwo::greaterThanFive };
ProcessorTwo functionPointerTwo{ ProcessorTwo::lessThanFive };
std::cout << "Process 4 with One: " << (functionPointerOne.process(4) ? "True" : "False") << std::endl;
std::cout << "Process 4 with Two: " << (functionPointerTwo.process(4) ? "True" : "False") << std::endl;
}
我会知道编译时会用到的函数。我对 C++ 还很陌生,所以我不太了解这两种方法之间的区别。我听说函数指针添加了一个间接层,但是保存函数的结构不也是如此吗?是否有更“惯用”的 c++ 选项,或者它只是取决于开发人员的偏好?
主要区别在于模板版本使用“编译时多态性”,这意味着策略的选择发生在编译时并且策略是类型的一部分。因此,Processor<T>
的特定实例使用的策略必须在编译时已知,并且在创建 Processor<T>
后不能动态更改。
但是,您可以添加一个成员函数,以便 ProcessorTwo
使用的策略可以动态更改。例如,您还可以编写一个函数,该函数将 std::function<bool(int)>
作为参数并在函数体中创建一个 ProcessorTwo
;您不能使用 Processor<T>
执行此操作,除非它是函数模板。
因此,如果您需要那种动态性,函数指针或基于 std::function
的方法是可行的方法,但如果您不需要它,那么模板版本会更有效,因为调用策略不会涉及运行时间接。
我正在用 C++ 实现一个策略设计模式,我发现了几个我可以采用的不同选项。一种方法是使用模板,可能如下所示:
namespace Strategies
{
struct IsEven
{
bool doSomething(int x) { return x % 2 == 0; }
};
struct IsOdd
{
bool doSomething(int y) { return y % 2 == 1; }
};
}
template<typename Strategy>
class Processor
{
public:
Processor() : _strat{ Strategy() }
{}
bool process(int num)
{
return _strat.doSomething(num);
}
private:
Strategy _strat;
};
int main()
{
Processor<Strategies::IsEven> templateOne{};
Processor<Strategies::IsOdd> templateTwo{};
std::cout << "Process 4 with One: " << (templateOne.process(4) ? "True" : "False") << std::endl;
std::cout << "Process 4 with Two: " << (templateTwo.process(4) ? "True" : "False") << std::endl;
}
另一种方法是使用函数指针,可能如下所示:
#include <functional>
class ProcessorTwo
{
public:
using StrategyFunction = std::function<bool(int)>;
static bool lessThanFive(int num) {
return num < 5;
}
static bool greaterThanFive(int num) {
return num > 5;
}
ProcessorTwo(StrategyFunction strat) : _strat{ strat }
{}
bool process(int num) {
return _strat(num);
}
private:
StrategyFunction _strat;
};
int main()
{
ProcessorTwo functionPointerOne{ ProcessorTwo::greaterThanFive };
ProcessorTwo functionPointerTwo{ ProcessorTwo::lessThanFive };
std::cout << "Process 4 with One: " << (functionPointerOne.process(4) ? "True" : "False") << std::endl;
std::cout << "Process 4 with Two: " << (functionPointerTwo.process(4) ? "True" : "False") << std::endl;
}
我会知道编译时会用到的函数。我对 C++ 还很陌生,所以我不太了解这两种方法之间的区别。我听说函数指针添加了一个间接层,但是保存函数的结构不也是如此吗?是否有更“惯用”的 c++ 选项,或者它只是取决于开发人员的偏好?
主要区别在于模板版本使用“编译时多态性”,这意味着策略的选择发生在编译时并且策略是类型的一部分。因此,Processor<T>
的特定实例使用的策略必须在编译时已知,并且在创建 Processor<T>
后不能动态更改。
但是,您可以添加一个成员函数,以便 ProcessorTwo
使用的策略可以动态更改。例如,您还可以编写一个函数,该函数将 std::function<bool(int)>
作为参数并在函数体中创建一个 ProcessorTwo
;您不能使用 Processor<T>
执行此操作,除非它是函数模板。
因此,如果您需要那种动态性,函数指针或基于 std::function
的方法是可行的方法,但如果您不需要它,那么模板版本会更有效,因为调用策略不会涉及运行时间接。