У меня есть пользовательский интерфейс с древовидным представлением слева и средством просмотра справа (немного похоже на почтовый клиент).Вьюер справа отображает детали того, что я выбрал в дереве слева.
В пользовательском интерфейсе есть кнопки «добавить», «изменить» и «удалить».Эти кнопки действуют по-разному в зависимости от того, какой «узел» в дереве выбран.
Если у меня выбран узел определенного типа, а пользователь нажимает «изменить», то мне нужно открыть соответствующий диалог редактирования.для этого конкретного типа узла, с деталями этого узла.
Теперь, есть много разных типов узлов, и реализация класса посетителя кажется немного грязной (в настоящее время мой посетитель имеет около 48 записей ....).Это работает хорошо, хотя - в основном для редактирования есть что-то вроде класса OpenEditDialog, который наследует посетителя, и открывает соответствующий диалог редактирования:
abstractTreeNode-> accept (OpenEditDialog ());
Проблема в том, что мне нужно реализовать абстрактный класс посетителя для каждого «действия», которое я хочу выполнить на узле, и по какой-то причине я не могу не думать, что мне не хватает трюка.
Другой способ могЧтобы реализовать функции в самих узлах:
abstractTreeNode->openEditDialog();
Здесь я расскажу немного об узле, так что, может быть, это лучше:
abstractTreeNode->editClickedEvent();
Я не могупомогите, но подумайте, что это загрязняет узел.
Я действительно думал о третьем способе, о котором я еще не думал так много.Вместо этого у меня может быть шаблонный класс-обертка, который добавляется в дерево, что позволяет мне, возможно, вызывать free-функции для выполнения любых действий, поэтому я предполагаю, что он действует как переход между узлами и интерфейсом:
(псевдокод на макушке, просто чтобы дать представление):
template <class T>
TreeNode(T &modelNode)
{
m_modelNode = modelNode;
}
template <>
void TreeNode<AreaNode>::editClickedEvent()
{
openEditDialog(m_modelNode); // Called with concrete AreaNode
}
template <>
void TreeNode<LocationNode>::editClickedEvent()
{
openEditDialog(m_modelNode); // Called with concrete LocationNode
}
и т. д.
Таким образом, это эффективно расширяет узлы, но отличается от использования посетителя иэто кажется немного более аккуратным.
Теперь, прежде чем я продолжу и сделаю решительный шаг, используя один из этих методов, я подумал, что было бы разумно получить некоторую информацию.
Спасибо!Я надеюсь, что все это имеет некоторый смысл ..
РЕДАКТИРОВАТЬ:
Я смоделировал идею шаблонной оболочки ..
class INode
{
public:
virtual ~INode() {}
virtual void foo() = 0;
};
class AreaNode : public INode
{
public:
AreaNode() {}
virtual ~AreaNode() {}
void foo() { printf("AreaNode::foo\r\n"); }
};
class RoleNode : public INode
{
public:
RoleNode() {}
virtual ~RoleNode() {}
void foo() { printf("RoleNode::foo\r\n"); }
};
class ITreeNode
{
public:
virtual ~ITreeNode() {}
virtual void bar() = 0;
virtual void foo() = 0;
};
template <class T>
class MainViewTreeNode : public ITreeNode
{
public:
MainViewTreeNode() : m_node() {}
virtual ~MainViewTreeNode() {}
void bar() {}
void foo() { m_node.foo(); }
protected:
T m_node;
};
template <>
void MainViewTreeNode<AreaNode>::bar()
{
printf("MainViewTreeNode<AreaNode>::bar\r\n");
}
template <>
void MainViewTreeNode<RoleNode>::bar()
{
printf("MainViewTreeNode<RoleNode>::bar\r\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
MainViewTreeNode<RoleNode> role;
MainViewTreeNode<AreaNode> area;
std::list<ITreeNode*> nodes;
nodes.push_back(&role);
nodes.push_back(&area);
std::list<ITreeNode*>::iterator it = nodes.begin();
for (; it != nodes.end(); ++it)
{
(*it)->foo();
(*it)->bar();
}
getchar();
return 0;
}
Спасибо.