c++ - 如何实例化基于输入的策略模式
问题描述
示例通常完全忽略了策略模式的实例化。假设有一个输入定义了要使用的类。我们会有一些类似的东西:
class Strategy {
Strategy(){}
virtual void runAlgorithm() = 0;
};
class A : public Strategy {
A () {}
static bool isA(char input){ return input == 'A'; }
void runAlgorithm { /* Do A algorithm */ }
};
class B : public Strategy {
B () {}
static bool isB(char input){ return input == 'B'; }
void runAlgorithm { /* Do B algorithm */ }
};
// Other algorithms
Strategy* createStrat(char input){
Strategy* instance;
// Define which algorithm to use
if (A::isA(input)) {
instance = A();
} else if (B::isB(input)) {
instance = B();
} ...
// Run algorithm
instance.runAlgorithm();
return instance;
}
正如你所看到的,如果我们有多种不同的算法,这个 if/switch 会变得非常大。是否有一种模式可以使此代码更易于人工解析(即,for 循环和调用)而不添加对数组?该问题还可以扩展到“如何实例化基于输入的策略模式?”
不要局限于此代码,因为它只是一个示例。
解决方案
好的,如果您事先知道所有策略,您可以使用非常简单的元编程递归来自动展开您的 if-else 链。开始了:
#include <string_view>
#include <iostream>
#include <exception>
#include <memory>
struct Strategy {
Strategy(){}
virtual void runAlgorithm() = 0;
};
struct A : public Strategy {
A () {std::cout << "Creating A" << std::endl;}
static constexpr std::string_view id(){
return std::string_view("A");
}
void runAlgorithm() { /* Do A algorithm */ }
};
struct B : public Strategy {
B () {std::cout << "Creating B" << std::endl;}
static constexpr std::string_view id(){
return std::string_view("B");
}
void runAlgorithm() { /* Do B algorithm */ }
};
struct C : public Strategy {
C () {std::cout << "Creating C" << std::endl;}
static constexpr std::string_view id(){
return std::string_view("C");
}
void runAlgorithm() { /* Do C algorithm */ }
};
// the if else chains are constructed by recursion
template <class Head, class... Tail>
struct factory {
static std::unique_ptr<Strategy> call(std::string id) {
if(Head::id() == id) return std::make_unique<Head>();
else return factory<Tail...>::call(id);
}
};
// specialization to end the recursion
// this throws an exception, but you can adapt it to your needs
template <class Head>
struct factory<Head> {
static std::unique_ptr<Strategy> call(std::string id) {
if(Head::id() == id) return std::make_unique<Head>();
else throw std::invalid_argument("The strategy id you selected was not found.");
}
};
// here is your factory which can create instances of A,B,C based only on the runtime id
using my_factory = factory<A,B,C>;
int main() {
auto Astrategy = my_factory::call("A");
auto Bstrategy = my_factory::call("B");
auto Cstrategy = my_factory::call("C");
my_factory::call("D"); // exception thrown
}
现场代码在这里
编辑
按照 Jarod42 的建议进行了编辑以考虑智能指针和错误检查。
推荐阅读
- android - Android Imageview和Buttons在同一个View
- python - 通过解释器运行文件会更改当前目录?
- assembly - 装配体中的嵌套 If 块
- matlab - 计算 BMI MATLAB
- python - 为什么这段代码不在这一行之后运行?
- javascript - javascript:仅按第一个空格拆分句子并插入到同一个列表中。功能性方法
- r - 使用 ggplot 包制作箱线图时的 aes() 值是什么?
- image - 为纸张导出 Matlab 图像
- encryption - 错误:“解码错误(36):字典不匹配”在命令行上使用 ZSTD 解码来解码 .ZST 文件
- python - 从父目录导入时出现 Python3 ModuleNotFoundError