从复合图案结构中删除元素

Vid*_*dak 5 c++ oop algorithm inheritance design-patterns

假设我们有最简单的结构,类Component,Leaf : ComponentComposite : Component.Leaf类的每个对象都有一个int id赋予它标识的对象.复合类会像:

class Composite : public Component
{
public:
    void removeComponent(Component*);
// other stuff
private:
    std::vector<Component*> coll;
};
Run Code Online (Sandbox Code Playgroud)

和叶班一样:

class Leaf : public Component
{
public:
    //stuff
    int getID();
private:
    int id;
};
Run Code Online (Sandbox Code Playgroud)

问题是如何定义功能removeComponent(Component* cmp).cmp实际上是一个Leaf,但我需要访问Component矢量coll,所以它需要是一个Component(我认为).removeComponent方法接受一个Leaf对象,并从整个结构中删除具有相同ID的所有其他Leaves.

现在,我想到了两种方式(两者都不起作用:P):

第一

void Composide::removeComponent(Component* cmp)
{
    std::vector<Component*>::const_iterator it;
    for(it = coll.begin(); it != coll.end(); ++it)
    {
        (*it)->removeComponent(cmp);
    // where removeComponent is defined as virtual in Component, but
    // the problem is that Leaf cannot erase itself from the collection
    }

}
Run Code Online (Sandbox Code Playgroud)

第二

void Composide::removeComponent(Component* cmp)
    {
        std::vector<Component*>::const_iterator it;
        for(it = coll.begin(); it != coll.end(); ++it)
        {
            if((*it)->equals(*cmp))
            it = erase(it);
        // But here I can't define equals function for Composite elements,
    // so then I'd have to make functions which return the type of Component,
    // and in case of Composite call recursively the function and
    // in the case of Leaf call the equals() function and erase if needed.
    // This however looks like really bad OOP practice, and I'd like to avoid
    // using those methods which return type..
        }

    }
Run Code Online (Sandbox Code Playgroud)

必须有一个整洁,美好的方式来做到这一点.我认为该方法应该看起来像上面提到的第一种方式,只是我真的不知道如何启用Leaf从向量中删除自己.请帮帮我?:)

Gaz*_*yer 3

您似乎对到底是什么感到困惑Component。它是某个业务对象,还是代表树节点的类?如果它是一个树节点,那么所有树节点应该支持相同的操作以允许轻松递归。

因此,我会将 的定义移至removeComponent()Component类并使其成为虚拟的。您可以在 中提供一个空的实现Component

那么您的复合实现就很简单:

void Composide::removeComponent(Component* cmp)
{
    std::vector<Component*>::const_iterator it;
    for(it = coll.begin(); it != coll.end(); ++it)
    {
        if((*it)->equals(*cmp))
           it = erase(it);
        else
           (*it)->removeComponent(cmp);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:关于 ID

同样,我认为您可能混淆了两个概念:组件 id 和组件。Component(也许改名为会更好TreeItem?)

您当前的removeComponent()函数采用一个Component指针,从而推断任何Component可以从树中删除(包括Composites)。这对我来说似乎是正确的。您可能很需要删除Composites. 因此,您可以简单地比较指针。

但是,您似乎正在比较仅Leafs具有的 Id(通过假定的相等重载)。

如果您想提供一个按 Id 删除的附加函数,那么我也将 GetID() 函数移至基Component类,并与之进行比较。Composite对象可以返回 -1 或其他一些空标记。

例如。

void Composite::getID()
{
   return -1;
}

void Composide::removeComponent(Component* cmp)
{
    std::vector<Component*>::const_iterator it;
    for(it = coll.begin(); it != coll.end(); ++it)
    {
        if((*it) == cmp)
           it = erase(it);
        else
           (*it)->removeComponent(cmp);
    }
}

void Composite::removeComponentById(int id)
{
    std::vector<Component*>::const_iterator it;
    for(it = coll.begin(); it != coll.end(); ++it)
    {
        if((*it)->getID() == id)
           it = erase(it);
        else
           (*it)->removeComponentById(id);
    }
}
Run Code Online (Sandbox Code Playgroud)