实现在树节点上执行操作的最佳方式,最好不使用访问者 [英] Best way to implement performing actions on tree nodes, preferably without using visitors

查看:109
本文介绍了实现在树节点上执行操作的最佳方式,最好不使用访问者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个左侧有一个树视图的用户界面,右侧有一个查看器(有点像电子邮件客户端)。

I have a user interface with a tree view on the left, and a viewer on the right (a bit like an email client). The viewer on the right displays the detail of whatever I have selected in the tree on the left.

用户界面具有添加,编辑和删除纽扣。

The user interface has "add", "edit" and "delete" buttons. These buttons act differently depending on what "node" in the tree is selected.

如果我选择了一个特定类型的节点,并且用户点击编辑那么我需要为该节点的详细信息打开相应的编辑对话框。

If I have a node of a particular type selected, and the user clicks "edit", then I need to open the appropriate edit dialog for that particular type of node, with the details of that node.

现在,有很多不同类型的节点和实现一个访客类感觉有点凌乱(currenty我的访问者有大约48个条目....)。它可以很好地工作,但基本上是编辑一个像继承访问者的OpenEditDialog类,并打开相应的编辑对话框:

Now, there's a lot of different types of node and implementing a visitor class feels a bit messy (currenty my visitor has about 48 entries....). It does work nicely though - basically for editing a have something like an OpenEditDialog class that inherits the visitor, and opens the appropriate edit dialog:

abstractTreeNode-> accept(OpenEditDialog ));

abstractTreeNode->accept(OpenEditDialog());

问题是我必须为节点上的每个动作实现抽象访问类,由于某种原因我不能帮助认为我缺少一个招数。

The problem is I have to implement the abstract visitor class for every "action" I want to perform on the node and for some reason I can't help thinking I'm missing a trick.

另一种方法是在节点本身实现函数:

The other way could of been to implement the functions in the nodes themselves:

abstractTreeNode->openEditDialog();

我在这里找到一个节点,所以也许这更好:

I'm ording the node around a bit here, so maybe this is better:

abstractTreeNode->editClickedEvent();

我不禁想到这是污染节点。

I can't help but think this is polluting the node though.

我想到了第三种方式,我还没有给出太多的想法。我可以有一个模板化的包装类,添加到树,而不是允许我可能调用自由函数来执行任何操作,所以我想,它作为一个去节点和接口之间:

I did think of a third way that I've not given that much thought yet. I could have a templated wrapper class that gets added to the tree instead which allows me to perhaps call free-functions to perform whatever actions, so I guess as it acts as a go between for nodes and interface:

(我的头顶的伪代码只是为了给出一个想法):

(pseudo code off the top of my head just to give an idea):

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
}

等。

因此,这是有效地扩展节点,但以不同的方式使用访问者,它似乎有点整洁。

So this is effectively extending the nodes but in a different way to using the visitor and it seems a little bit neater.

使用其中的一种方法,我认为这是明智的,以获得一些输入。

Now before I go ahead and take the plunge using one of these methods, I thought it'd be wise to get some input.

谢谢!我希望所有这些都有一些意义。

Thanks! I hope all this makes some sense..

编辑:

我模拟了模板封装的想法..

I've mocked up the templated wrapper idea..

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;
}

感谢。

推荐答案

访问者在您 多个操作 。如果你有很多类型,但操作很少,使用正态多态性。

Visitor is useful when you have many operations and few types. If you have many types, but few operations, use normal polymorphism.

这篇关于实现在树节点上执行操作的最佳方式,最好不使用访问者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆