5

最も単純な構造のクラスComponentと があるLeaf : ComponentとしComposite : Componentます。Leafクラスの各オブジェクトにはint id、そのアイデンティティを与える があります。複合クラスには、次のような sth があります。

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 は実際には ですが、ベクトル collLeafにアクセスする必要があるため、 (だと思います) である必要があります。removeComponent メソッドはオブジェクトを受け取り、構造全体から同じ ID を持つ他のすべての葉を削除します。ComponentComponentLeaf

今、私は2つの方法を考えました(どちらも機能しません: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
    }

}

2番

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について

繰り返しになりますが、コンポーネント ID とコンポーネントという 2 つの概念を混乱させているのではないかと思います。Component(改名したほうがいいかもTreeItem?)

現在のremoveComponent()関数はポインターを受け取るため、ツリーから削除できるものがあるとComponent推測されます ( を含む)。これは私には正しいようです。を削除する必要があるかもしれません。したがって、ポインターを単純に比較できます。ComponentCompositesComposites

しかし、あなたは(仮定された等価オーバーロードを介して)Leafs持っているだけのIDを比較しているようです。

Id で削除する追加の関数を提供する場合は、GetID() 関数も基本Componentクラスに移動し、それと比較します。Compositeオブジェクトは -1 またはその他の null マーカーを返すことができます。

例えば。

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(..) メソッドは、Component 内で純粋に仮想化され、各子に実装される必要があります。

編集: 反復検索用に if/else を追加

于 2012-09-11T08:57:29.647 に答える