5

假设我们有最简单的结构、ComponentLeaf : ComponentComposite : Component。类的每个对象Leaf都有一个int id赋予它身份的对象。复合类将具有以下内容:

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

和叶子类的东西像:

class Leaf : public Component
{
public:
    //stuff
    int getID();
private:
    int id;
};

问题是如何定义函数removeComponent(Component* cmp)。cmp 实际上是 a Leaf,但我需要访问Component向量 coll,所以它必须是 a Component(我认为)。removeComponent 方法接受一个Leaf对象,并从整个结构中移除所有其他具有相同 ID 的叶子。

现在,我想到了两种方法(这两种方法都不起作用: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
    }

}

第二

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

    }

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

4

2 回答 2

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

编辑:关于身份证

同样,我认为您可能混淆了两个概念,即组件 ID 和组件。(也许你改名会更好ComponentTreeItem

您当前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);
    }
}
于 2012-09-11T09:03:34.380 回答
-1

我会采用这种方法:

void Composide::removeComponent(Component* cmp)
{
    std::vector<Component*>::const_iterator it;
    for(it = coll.begin(); it != coll.end(); ++it)
    {
        if((*it)->equals(*cmp))
        {
            delete *it;
            coll.erase(it);
            return;//can there be more than one?
        }
        else
        {
            //iterative call
            it->removeComponent(*cmp);
        }
    }
}

void Composide::~Composite()
{
    std::vector<Component*>::const_iterator it;
    for(it = coll.begin(); it != coll.end(); ++it)
    {
        delete *it;
        it = coll.erase(it);
    }
}

如果 Composite 被删除,Composite 的析构函数应该处理它自己的所有子组件。

一般来说,我会推荐使用智能指针。不再需要删除。

equals(..) 方法应该在组件中是纯虚拟的,并在每个子项中实现。

编辑:为迭代搜索添加了 if/else

于 2012-09-11T08:57:29.647 回答