假设我们有最简单的结构,类Component
,Leaf : Component
和Composite : 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实际上是Leaf
,但我需要访问Component
向量coll,所以它需要是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
从向量中删除自己。请帮帮我? :)
答案 0 :(得分: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的
同样,我认为你可能会混淆两个概念,即组件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);
}
}
答案 1 :(得分:-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(..)方法不应该是Component中的纯虚方法,而是在每个子节点中实现。
编辑:添加if / else进行迭代搜索