在树节点上实现执行操作的最佳方法,最好不使用访问者

Mar*_*ark 6 c++ oop design-patterns

我有一个左侧有树视图的用户界面,右侧有一个查看器(有点像电子邮件客户端).右侧的查看器显示我在左侧树中选择的任何内容的详细信息.

用户界面具有"添加","编辑"和"删除"按钮.这些按钮的行为取决于树中选择的"节点".

如果我选择了特定类型的节点,并且用户单击"编辑",那么我需要为该特定类型的节点打开相应的编辑对话框,其中包含该节点的详细信息.

现在,有很多不同类型的节点,并且实现访问者类感觉有点乱(当前我的访问者有大约48个条目....).它确实很好用 - 基本上用于编辑类似于继承访问者的OpenEditDialog类,并打开相应的编辑对话框:

abstractTreeNode->接受(OpenEditDialog());

问题是我必须为我想要在节点上执行的每个"动作"实现抽象访问者类,并且出于某种原因我不禁想到我错过了一个技巧.

另一种方法是在节点本身中实现这些功能:

abstractTreeNode->openEditDialog();
Run Code Online (Sandbox Code Playgroud)

我在这附近点了节点,所以也许这更好:

abstractTreeNode->editClickedEvent();
Run Code Online (Sandbox Code Playgroud)

我不禁想到这会污染节点.

我确实想到了第三种方式,我还没有多想过.我可以有一个被添加到树来代替,让我或者叫自由函数来执行任何操作的模板包装类,所以我想,因为它充当节点和接口之间一展身手:

(伪代码在我脑海中只是为了给出一个想法):

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
}
Run Code Online (Sandbox Code Playgroud)

等等..

所以这有效地扩展了节点,但以不同的方式使用访问者,它看起来有点整洁.

现在我继续前进,采取使用这些方法之一尝试之前,我想那会是明智的,得到一些输入.

谢谢!我希望这一切都有一定意义..

编辑:

我嘲笑了模板包装的想法..

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;
}
Run Code Online (Sandbox Code Playgroud)

谢谢.

sbi*_*sbi 2

当您有很多操作很少的类型时,访问者很有用。如果您有很多类型,但很少有操作,请使用普通的多态性。