我有一组硬件处理程序类,它们都是从基类派生的,必须响应传入的数据包。此数据包的一部分是ASCII字符串,它确定硬件处理程序的哪个成员函数用于处理数据包(例如“fan”将执行ToggleFan()
函数。
class HardwareHandler {
virtual void dispatchCommand(const String& cmd) = 0;
}
class FooblerHandler : public HardwareHandler {
void toogleFan();
void dispatchCommand(const String& cmd) {
//is this a "good" way to do this?
if (cmd == "fan")
toggleFan();
}
}
我使用JUCE作为框架,这意味着我有模板HashMap
和String
之类的东西。
但是,我无法想出一种基于此字符串选择正确处理函数的整洁方法。构造
if (str == "hello")
FooCommand();
else if (str == "bar")
BarCommand();
在概念上看起来很难看,因为那里有很多相对昂贵的字符串比较。但是,代码很容易编写,每个类的逻辑都保存在一个地方。
我尝试的另一种方法是将字符串的哈希映射制作为枚举并使用switch语句:
switch (str.getHash())
{
case CmdFoo:
FooCommnad();
break;
....and so on
}
然而,这也要求我设置一个静态哈希映射,并保持开关匹配。
我试过的其他东西是一个哈希映射,形成了成员函数指针本身的字符串,希望能够直接从字符串跳转到成员函数而不必在case语句中列出它们,并且还允许非常通用调度函数,因为它只需要在哈希映射中查找,它甚至不需要知道所有选项 - 它们只能包含在哈希映射中,这样我就可以将调度函数推送到基本处理程序类,不在每个特定的设备处理程序中重复自己但是,这个方法让我很难过,因为我无法理解如何正确地执行它,或者即使可以使用静态哈希映射和成员函数来执行此操作。
是否存在基于字符串(或类似的难以比较的类型)分派给成员函数的惯用方法,最好是尽可能多的逻辑能够被泛化并尽可能地移动到父类?
答案 0 :(得分:1)
这是我的尝试。您可以将映射机制封装到类中:
#include <iostream>
#include <string>
#include <functional>
#include <map>
class X;
template<class X>
class handler_factory;
template<>
class handler_factory<X>
{
private:
using HandlerType = void (X::*)();
public:
handler_factory();
HandlerType get(const std::string& name) const
{
if (handlers.find(name) == handlers.end())
return nullptr;
else
return (*handlers.find(name)).second;
}
private:
std::map<std::string, HandlerType> handlers;
};
class X
{
public:
friend class handler_factory<X>;
private:
void f();
void h();
};
handler_factory<X>::handler_factory()
{
handlers["f"] = &X::f;
handlers["h"] = &X::h;
}
void X::f() { std::cout << "X::f();"; }
void X::h() { std::cout << "X::h();"; }
您的调度方法可以实现为:
void dispatch_method(const std::string& name)
{
if (find_handler(name))
(this->*find_handler(name))();
}
int main()
{
X().dispatch_method("f");
}
将find_handler
定义为私有帮助方法:
private:
auto find_handler(const std::string& name)
-> decltype(handler_factory<X>().get(name))
{
return handler_factory<X>().get(name);
}
答案 1 :(得分:0)
我认为解决问题的最有效方法是创建一个std::map
,将您的字符串映射到适当的函数中。该方法速度快(由于采用对数搜索算法),简单安全。
class FooblerHandler : public HardwareHandler {
typedef void (HardwareHandler::*function)();
map<string,function> commandMap;
void dispatchCommand(const string& cmd) {
if(commandMap.count(cmd))
(this->*commandMap.find(cmd)->second)();
else
cout << "No command found with name \"" <<cmd<< "\"." << endl;
}
};
当然你应该在构造函数内部(或在使用之前的某个地方)初始化地图:
commandMap["fan"] = &FooblerHandler::toogleFan;
commandMap["someOtherCommand"] = &FooblerHandler::otherFunction;
Maps并包含在几乎所有IDE供应的标准模板库(STL)中。
修改强> 我最后没看完文字。好吧 - 现在你知道了语法:)