如何实例化基于输入的策略模式
How to instantiate input based strategy pattern
示例通常完全忽略了策略模式的实例化。假设有一个输入定义了要使用的类。我们会有一些类似的东西:
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的建议,对智能指针和错误检查进行了编辑。
是的,有一个解决方案。有几种方法可以做到这一点。模板在其他类或这种方式:
class StrategyMaker {
public:
void register(std::funcion<bool(char)> predicate,
std::function<std::unique_ptr<Strategy>(char)> factory) {
mFactories.push_back(std::make_pair(std::move(predicate), std::move(factory)));
}
std::unique_ptr<Strategy> create(char ch) {
for (auto pair & : mFactories) {
if (pair.first(ch)) {
return pair.second(ch);
}
}
return {};
}
private:
std::vector<std::pair<std::funcion<bool(char)>,
std::function<std::unique_ptr<Strategy>(char)>>> mFactories;
};
StrategyMaker maker;
maker.register([](char ch){ return input == 'A'; },
[](char ch){ return std::unique_ptr(new A); });
有一次我看到一篇很好的文章,展示了如何使它完全自动。我发现了这样的东西(我不能100%确定这是我前段时间读到的(。
相关文章:
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 检查输入是否不是整数或数字
- 正在尝试了解输入验证循环
- 读取文件并输入到矢量中
- C++如何通过用户输入删除列表元素
- 用c++从输入文件中读取另一行
- 读取文件的最后一行并输入到链接列表时出错
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何使用用户输入在C++中正确填充2D数组
- C++MySQL C api用户输入行
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 用户定义函数中的指针和输入
- 如何在C++中检查2D数组中负值的输入验证
- 如何只允许用户输入正整数
- 如何实例化基于输入的策略模式
- 暴力迫使程序以不同的输入崩溃的策略是什么?
- 使用策略设计模式实现输入类
- Boost Wave自定义输入策略