如何使当前的编码结构更灵活 [英] How to make the current coding structure more flexible
问题描述
我需要当前工作流程的帮助,尽管一切都可以按预期进行,但我想使结构更坚固.
I need help with my current workflow , though everthing works as expected but i would like to make the structure more robust.
我有一个应用程序,在其中我可以通过字符串文字来更改数据.
I have a application where i change the data by string literal.
WAVEFRONT*TREEVIEW*Main$Text*GEOMETRY*TEXT SET TEXT ABCD
如图所示,其中"Main $ Text"是树结构的数据项的路径.
as shown in the image where "Main$Text" is the path of the data item the the tree structure.
1)第一步->我有一个类来处理命令字符串并采取适当的措施.
1) First step-> i have a class to handle the command string and take appropriate action.
int SumCommandInterface::receiveCommand(std::string stdtsrCommand , const QModelIndex & RootIndex, TreeModel *myModel)
{
std::vector<std::string> vectorStrCommand;
std::vector<std::string> vectorStrStarSplit;
std::vector<std::string> vectorStrContainerNames;
boost::algorithm::trim(stdtsrCommand);
boost::split(vectorStrCommand, stdtsrCommand, boost::is_any_of(" "), boost::token_compress_on);
boost::split(vectorStrStarSplit, vectorStrCommand[0], boost::is_any_of("*"), boost::token_compress_on);
if (vectorStrStarSplit[1] == "TREEVIEW") // for tree view
{
if (vectorStrCommand.size() < 4)
return -1;
boost::split(vectorStrContainerNames, vectorStrStarSplit[2], boost::is_any_of("$"), boost::token_compress_on);
TreeItem* itm;
QModelIndex Index = RootIndex;
for (auto &strName : vectorStrContainerNames)
{
if (!getTreeItem(strName, Index, myModel, &itm))
{
return 0;
}
Index = myModel->indexForTreeItem(itm);
}
PluginTypeLookUp lookUp = lookUpPluginMap[vectorStrStarSplit[3]];
Container *cont = itm->GetContainer();
switch (lookUp)
{
case PluginTypeLookUp::GEOMTERY: // This can be function , texture etc, currently only showing code for geometry
{
Geometry *geom = cont->GetGeometry();
if(vectorStrCommand[2] == "TEXT" )
setFontPluginParam< Geometry , std::string >( geom, vectorStrCommand[2], vectorStrCommand[3]);
if (vectorStrCommand[2] == "USESHADOW")
setFontPluginParam< Geometry , bool >(geom, vectorStrCommand[2], (vectorStrCommand[3] == "0" ? false : true) );
if (vectorStrCommand[2] == "FONTSIZE" || vectorStrCommand[2] == "SHADOWDIRECTION")
setFontPluginParam< Geometry, int >(geom, vectorStrCommand[2], std::stoi(vectorStrCommand[3]) );
if (vectorStrCommand[2] == "SHADOWDISTANCE" || vectorStrCommand[2] == "SHADOWOPACITY" || vectorStrCommand[2] == "KERNING" )
setFontPluginParam< Geometry, float >(geom, vectorStrCommand[2], std::stof(vectorStrCommand[3]));
}
break;
case PluginTypeLookUp::TEXTURE:
{
Sum_Texture_2D *texture;
texture = cont->GetTexturePointer();
if(vectorStrCommand[2] == "TEXTUREPATH" )
setTexturePluginParam< Sum_Texture_2D, std::string >(texture, vectorStrCommand[2], vectorStrCommand[3]);
if (vectorStrCommand[2] == "POSITIONX" || vectorStrCommand[2] == "POSITIONY" || vectorStrCommand[2] == "POSITIONZ" || vectorStrCommand[2] == "SCALINGX" || vectorStrCommand[2] == "SCALINGY" || vectorStrCommand[2] == "SCALINGZ" || vectorStrCommand[2] == "ROTATIONX" || vectorStrCommand[2] == "ROTATIONY" || vectorStrCommand[2] == "ROTATIONZ ")
{
setTexturePluginParam< Sum_Texture_2D, float >(texture, vectorStrCommand[2], std::stof(vectorStrCommand[3]));
}
break;
}
default:
break;
}
return 1;
}
return 0;
}
我在命令中传递了几何参数,并据此获得了if条件.
i am passing the geometry parameter in command and based on that i have a if condition.
例如USESHADOW的命令如下所示.
for example for USESHADOW the command would look like.
WAVEFRONT*TREEVIEW*AMain$Text*GEOMETRY*TEXT SET USESHADOW 1
如果Geometry参数为TEXT,则命令如下所示.
if Geometry parameter is TEXT the command would look like.
WAVEFRONT*TREEVIEW*AMain$Text*GEOMETRY*TEXT SET TEXT ABC
case PluginTypeLookUp::GEOMTERY: // This can be function , texture
etc, currently only showing code for geometry
{
Geometry *geom = cont->GetGeometry();
if(vectorStrCommand[2] == "TEXT" )
setFontPluginParam< Geometry , std::string >( geom, vectorStrCommand[2], vectorStrCommand[3]);
if (vectorStrCommand[2] == "USESHADOW")
setFontPluginParam< Geometry , bool >(geom, vectorStrCommand[2], (vectorStrCommand[3] == "0" ? false : true) );
if (vectorStrCommand[2] == "FONTSIZE" || vectorStrCommand[2] == "SHADOWDIRECTION")
setFontPluginParam< Geometry, int >(geom, vectorStrCommand[2], std::stoi(vectorStrCommand[3]) );
if (vectorStrCommand[2] == "SHADOWDISTANCE" || vectorStrCommand[2] == "SHADOWOPACITY" || vectorStrCommand[2] == "KERNING" )
setFontPluginParam< Geometry, float >(geom, vectorStrCommand[2], std::stof(vectorStrCommand[3]));
}
break;
我当前面临的问题是,如果我有30个不同的几何参数,那么如果条件需要添加30个.
The current issue i am facing is that if i have 30 different geometry parameters i would need to add 30 if conditions.
如果我添加更多几何类型,我将再次需要重新访问此代码并添加更多参数.
If i add more geometry types i would again need to revisit this code and add more parameters.
我能以更优雅的方式处理此步骤吗?
can i handle this step in more graceful way.
推荐答案
基本的映射查找.这些使基于表的菜单系统和简单的解析器变得非常出色.它们可能不是最快的,但是代码确实很简单 1 ,易于阅读,而且很难搞清楚.添加新命令或关键字就像在 map
的初始化程序中添加另一行一样简单.
A basic mapped look-up. These make great table-based menu systems and simple parsers. They may not be the fastest, but the code is really simple1, easy to read, and hard to screw up. Adding a new command or keyword can be as simple as adding another line to the map
's initializer.
您需要的是:
- 一个
std :: map
,用于将输入文本与所需的行为链接起来. - 一堆具有相同原型的函数,可以执行所需的行为.当行为简单时,Lambda表达式是一个不错的选择,因为它们会将所有相关代码都放在一个地方
- A
std::map
to link the input text with the desired behaviour. - A bunch of functions all with the same prototype that execute the desired behaviours. Lambda expressions are a great option when the behavour is simple since they keep all of the related code in one place
我们在这里!
#include <map>
#include <functional>
#include <string>
#include <iostream>
#include <vector>
// standing in for setFontPluginParam
template<class T>
void template_func(const std::string& name, const T & data)
{
std::cout << name << ":" << data << std::endl;
}
// functions to convert the data to the correct type for template_func
void text_func(const std::string & name, const std::string & text)
{
std::cout << "text_func "; // make output easier to interpret
template_func(name, text); // call correct template specialization
}
void int_func(const std::string & name, const std::string & num)
{
std::cout << "int_func ";
template_func(name, std::stoi(num));
}
// maps the name to the function. Note: If you're not messing around with lambdas or
// member functions, an old school function pointer may work better that std::function
std::map<std::string, std::function<void(const std::string &, const std::string &)>> call_function =
{
{"TEXT", text_func},
{"INT", int_func},
// same as above, but with a lambda expression to keep everything all in one place
{"DOUBLE", [](const std::string & name, const std::string & num) {
std::cout << "double_func ";
template_func(name, std::stod(num));
}}
};
void demo(const std::vector<std::string> & vectorStrCommand)
{
// uses map to look up correct function, then calls it
// This is basically all that's left of the if/else if chain
call_function[vectorStrCommand[2]](vectorStrCommand[2], vectorStrCommand[3]);
}
int main()
{
demo({"whatever", "whatever", "INT", "42"});
demo({"whatever", "whatever", "TEXT", "I am the very model of a modern major general..."});
demo({"whatever", "whatever", "DOUBLE", "3.14"});
}
1 因为它很简单,所以最适合简单的事情.不要尝试编写这样的C ++编译器.
1 Because it's simple it works best for simple things. Don't try to write a C++ compiler like this.
这篇关于如何使当前的编码结构更灵活的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!