Шаблон C ++ для замены выбора типа среды выполнения для генератора GUI - PullRequest
0 голосов
/ 28 ноября 2018

Я создаю GUI Generator для некоторых данных, которые создаются из Node классов.Каждый подкласс Node представляет различный тип данных (например, StringNode, IntNode).

Во время выполнения я не знаю производных типов узлов.Я чувствую, что мое единственное решение состоит в том, чтобы иметь массивный список if операторов:

if (auto stringNode = dynamic_cast<StringNode*>(node)) {
    /* Generate text input */
} else if (auto intNode = dynamic_cast<IntNode*>(node)) {
    /* Generate spin box */
} 
// etc...

Это кажется неэффективным и требует тщательного упорядочения, поэтому производные типы выше типов, которые они наследуют.

Есть ли другой способ сделать это, который использует полиморфизм?

  • Генератор графического интерфейса пользователя не находится в библиотеке, где определено Node.GUI для каждого узла может быть уникальным для производного типа (например, средство выбора даты).

  • Я не могу добавить виртуальный метод generateGui() на узлах, так как это потребует создания GUIв библиотеке.

  • Я могу редактировать класс Node.

  • Node могут быть добавлены за пределы этой библиотеки и должны такжепозволяют генерировать их GUI.

  • Я смотрел на Шаблон посетителей и Шаблон стратегии , но я не думаю, что онибудет соответствовать, поскольку не все классы или генераторы GUI будут доступны в библиотеке.

1 Ответ

0 голосов
/ 28 ноября 2018

Я могу предложить эту реализацию:

enum class NodeType { Unknown, String, Int, Float };
using CreateFunc = void(*)(Node *node);
using TypeFunc = bool(*)(Node *node);

// define type-checkers:
bool IsStringNode(Node *node)
{
    return dynamic_cast<StringNode*>(node) != nullptr;
}
bool IsIntNode(Node *node)
{
    return dynamic_cast<IntNode*>(node) != nullptr;
}
bool IsFloatNode(Node *node)
{
    return dynamic_cast<FloatNode*>(node) != nullptr;
}


class GuiGenerator
{
public:
// define specific creators:
    static void CreateStringGui(Node *node) { cout << "Creating String Gui" << endl; }
    static void CreateIntGui(Node *node)  { cout << "Creating Int Gui" << endl; }
    static void CreateFloatGui(Node *node)  { cout << "Creating Float Gui" << endl; }
    //void Create(<Some other node>) {}
};

map<NodeType, CreateFunc> Creators =
{
    { NodeType::String, &GuiGenerator::CreateStringGui },
    { NodeType::Int, &GuiGenerator::CreateIntGui },
    { NodeType::Float, &GuiGenerator::CreateFloatGui }
};

NodeType GetType(Node *node)
{
    vector<pair<NodeType, TypeFunc>> types =
    {
        { NodeType::String, &IsStringNode },
        { NodeType::Int, &IsIntNode },
        { NodeType::Float, &IsFloatNode }
    };

    for(auto &a : types)
        if(a.second(node))
            return a.first;
    return NodeType::Unknown;
}

// And here is it: your simplified function
//
static void CreateGUI(Node *node)
{
    auto type = GetType(node);
    Creators[type](node);
}

И вы можете использовать это так:

Node *node1 = new StringNode();
Node *node2 = new IntNode();
Node *node3 = new FloatNode();

CreateGUI(node1);
CreateGUI(node2);
CreateGUI(node3);

Для упрощения не предусмотрена обработка ошибок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...