Ben*_*min 11 c++ design-patterns
有一些讨厌的遗留代码.
std::string xxx = GetCommand(); // get "CommandX";
if (xxx == "Command1")
{
return new Command1();
}
else if (xxx == "Command2")
{
return new Command2();
}
...
else if (xxx == "Command100")
{
return new Command100();
}
Run Code Online (Sandbox Code Playgroud)
我想改进这个代码结构.
有太多的比较.所以我把它们放到地图上.
for (int i = 0; i < GetCommandCount(); ++i)
{
// key is a command string
// value is a function pointer which creates it's instance
map.insert(command, a function pointer);
}
// then
ICommand* pCommand = map.getInstance(command);
Run Code Online (Sandbox Code Playgroud)
但是,如果有新的命令,这种方式必须每次都有额外的功能.是的,功能可能是合理的.但所有的功能只是return new CommandNNN();
我猜有删除重复的方法.
你怎么想?
Mag*_*off 10
由于所有功能都是return new CommandNNN();
,您可以使用模板功能:
template <class T>
CommandBase* createCommand() {
return new T();
}
Run Code Online (Sandbox Code Playgroud)
并绑定到地图中的此函数:
map.insert(std::make_pair("Command1", &createCommand<Command1>));
map.insert(std::make_pair("Command2", &createCommand<Command2>));
map.insert(std::make_pair("Command3", &createCommand<Command3>));
Run Code Online (Sandbox Code Playgroud)
这样可以避免为每个命令创建新函数.但是,map.insert
-statements中仍然存在一些重复.这可以通过使用宏来进一步减少,如果这是你的一杯茶:
#define INSERT(cmd) map.insert(std::make_pair(#cmd, &createCommand<cmd>));
INSERT(Command1);
INSERT(Command2);
INSERT(Command3);
#undef INSERT
Run Code Online (Sandbox Code Playgroud)
要么
#define INSERT(n) map.insert(std::make_pair("Command" #n, &createCommand<Command ## n>));
INSERT(1);
INSERT(2);
INSERT(3);
#undef INSERT
Run Code Online (Sandbox Code Playgroud)
我怀疑你甚至可以让预处理器为你做一些计数,但这不属于我的领域.
应用更多的宏,以及一些全球状态,这两者都被许多人所厌恶,你可以得到更紧密的耦合:
#include <map>
#include <string>
#include <cassert>
class CommandBase {};
static std::map<std::string, CommandBase* (*)()> g_commandMap;
template <class C>
CommandBase* createCommand() {
return new C();
}
class CommandRegistrer {
public:
CommandRegistrer(const std::string& name, CommandBase* (*instantiator)()) {
g_commandMap.insert(std::make_pair(name, instantiator));
}
};
#define COMMAND_CLASS(n) \
class Command##n; \
CommandRegistrer g_commandRegistrer##n("Command" #n, createCommand<Command##n>); \
class Command##n : public CommandBase
COMMAND_CLASS(1) { /* implementation here */ };
COMMAND_CLASS(2) { /* implementation here */ };
int main() {
assert(g_commandMap.find("Command1") != g_commandMap.end());
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的是C++ 11,则可以使用内联lambda来执行此操作,以便所有内容都在一个位置:
class Object
{
};
class Command1 : public Object
{
};
// etc
typedef std::map<std::string, std::function<Object*()>> FunctionMap;
typedef std::pair<std::string, std::function<Object*()>> FunctionPair;
FunctionMap funcMap;
funcMap.insert(FunctionPair("Command1", []()
{
return new Command1();
}));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
873 次 |
最近记录: |