C++ 中的复合模式

发布于 2024-08-30 07:22:43 字数 486 浏览 3 评论 0原文

我必须使用类似于电话簿的 C++ 应用程序:带有 STL 联系人列表的 Agenda 类。关于联系人层次结构,有一个名为 Contact 的基类(一个抽象类),以及派生类 Friend 和熟悉(接触的类型)。

例如,这些类有一个名为 getName 的虚拟方法,该方法返回联系人的姓名。

现在我必须通过添加另一种类型的联系人公司(派生自联系人)来实现复合模式,该联系人还包含联系人集合(也是 STL 列表),可以是以下任一类型: “叶子”类型(朋友或熟人),或者他们也可以是公司。

因此,Company 是Compound 类型。

问题是:如何以及在哪里实现 STL find_if 来搜索具有给定名称的联系人(通过 getName 函数或建议我其他方式)在“叶子”类型联系人和内部公司收藏?

换句话说,如何使用统一的函数定义遍历树以便在那里找到可能的匹配项?

我希望我说得很清楚......

I have to work with an application in C++ similar to a phone book: the class Agenda with an STL list of Contacts.Regarding the contacts hierarchy,there is a base-class named Contact(an abstract one),and the derived classes Friend and Acquaintance(the types of contact).

These classes have,for instance, a virtual method called getName,which returns the name of the contact.

Now I must implement the Composite pattern by adding another type of contact,Company(being derived from Contact),which also contains a collection of Contacts(an STL list as well),that can be either of the "leaf" type(Friends or Acquaintances),or they can be Companies as well.

Therefore,Company is the Compound type.

The question is: how and where can I implement an STL find_if to search the contact with a given name(via getName function or suggest me smth else) both among the "leaf"-type Contact and inside the Company collection?

In other words,how do I traverse the tree in order to find possible matches there too,using an uniform function definition?

I hope I was pretty clear...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

临风闻羌笛 2024-09-06 07:22:44

好吧,一种方法是:

virtual contact* contact::findContact(std::string name)
{
    if(m_name == name) {return this;}
    return NULL;
}

然后:

contact * Company::findContact(std::string name)
{
    if(!contact::findContact(name) )
    {
        //For each contact in the contact list, findContact(name)
        //If we find something, return that.
        //Otherwise return null.
    }
    return this;
}

您正在做的就是要求每个节点找到您正在寻找的节点,而不关心它是什么类型的节点(叶节点或其他节点)。然后,每个节点检查自身,并且对于具有子节点的节点,检查其子节点。

Well, one way to do it:

virtual contact* contact::findContact(std::string name)
{
    if(m_name == name) {return this;}
    return NULL;
}

Then:

contact * Company::findContact(std::string name)
{
    if(!contact::findContact(name) )
    {
        //For each contact in the contact list, findContact(name)
        //If we find something, return that.
        //Otherwise return null.
    }
    return this;
}

What you're doing is asking each node to find the one you're looking for, without caring what type of node (leaf or otherwise) it is. Each node then checks itself, and, for those with child nodes, their children.

撩起发的微风 2024-09-06 07:22:44

对于大量联系人来说,列表是错误的类型,因为您可能需要 O(N) 才能找到最后一个联系人,甚至找不到任何联系人。
我建议您使用哈希映射(来自 boost/tr1 的 unordered_map)或常规映射,这样您就可以使用键通过 ID 或名称找到它们。
听起来公司应该只是一棵联系人树。
您可以在此处找到树实现。
您遍历树以找到所需的节点。

List is the wrong type for a large type of contacts since you might have a O(N) to find the last contact or even to find no contact.
I suggest you to use a hash map (unordered_map from boost/tr1) or a regular map so you will be able to find them by ID or their name using a key.
Also sounds like a company should just be a tree of contacts.
You can find tree implementations here.
You transvase through the tree to find the node you need.

原谅过去的我 2024-09-06 07:22:44

“现在我必须通过添加另一种类型的联系人公司(派生自联系人)来实现复合模式,其中还包含联系人集合(也是 STL 列表),可以是“叶”类型(朋友)或熟人),或者他们也可以是公司”

您可以为公司创建一个与 stl 兼容的复合迭代器。

class Company : public Contact {
    std::list<Contact *> contactList;

    //snip...other private members
    friend class CompanyIterator;
    friend class ConstCompanyIterator;
  public:

     // nested iterator classes
     class CompanyIterator : public std::iterator<std::forward_iterator_tag, Contact *> {

          friend class Company;
          // pair<>.first is the iterator obtain by calling begin()
          // pair<>.second is the end iterator
          std::stack< std::pair< std::list<Contact *>::iterator, 
                      std::list<Contact *>::iterator> > iters_stack;

          Contact *pCurrentContact;
          Company *pCompany; // This is the top level company which will be iterated.

        public:

          explicit CompanyIterator(Company &c);

          // Required forward iterator methods follow
          CompanyIterator();
          CompanyIterator(const CompanyIterator&);
          CompanyIterator& operator=(const CompanyIterator& other);
          Contact &operator*() const;
          Contact *operator->() const;
          CompanyIterator& operator++();
          CompanyIterator operator++(int);

          bool operator==(const CompanyIterator& x) const;
          bool operator!=(const CompanyIterator& x) const;
     };

     // nested iterator class
     class ConstCompanyIterator : public std::iterator<std::forward_iterator_tag, 
          const Contact *> {

          friend class Company;
          // We use CompanyIterator to implement ConstCompanyIteraor  
           CompanyIterator inner_iter; // fwd operations here,
                                      // using "const_cast<Company *>(this)->method()"
        public:

          explicit ConstCompanyIterator(const Company & dir);

          // This ctor will function as a cast operator, to convert a CompanyIterator
          // into a ConstCompanyIterator
          ConstCompanyIterator(const CompanyIterator &iter);

          // Required forward iterator methods follow
          ConstCompanyIterator();
          ConstCompanyIterator(const ConstCompanyIterator&);
          ConstCompanyIterator& operator=(const ConstCompanyIterator& other);

          const Contact &operator*() const;
          const Contact *operator->() const;

          ConstCompanyIterator& operator++();
          ConstCompanyIterator operator++(int);

          bool operator==(const ConstCompanyIterator& x) const;
          bool operator!=(const ConstCompanyIterator& x) const;
     };

    typedef CompanyIterator iterator;
    typedef ConstCompanyIterator const_iterator;

    iterator begin();
    iterator end();

    const_iterator begin() const;
    const_iterator end() const;

    // snip... other Company public methods
};

对于上面给出的前向迭代器方法的实现,请参阅 Github 上的复合迭代器代码。大部分实现都在 Directory.cpp 中。 github 代码用于对文件系统进行建模的复合模式。类目录是复合的。文件类是叶类。 Node 类是基本组件类。

find_if 的函子看起来像

 FindIfFunctor {
      std::string name;
    public:
     FindIfFunctor(const std::string& n) : name(n) {} 
     bool operator()(const Contact& c) { return c.getName().compare(name); }
 }; 

最后,find_if 代码

 Company c;
 // snip... stuff gets added to company
 string someName("IBM");

 find_if(c.begin(), c.end(), FindIfFunctor(someName));

"Now I must implement the Composite pattern by adding another type of contact,Company(being derived from Contact),which also contains a collection of Contacts(an STL list as well),that can be either of the "leaf" type(Friends or Acquaintances),or they can be Companies as well"

You could create a stl-compatible composite iterator for Company.

class Company : public Contact {
    std::list<Contact *> contactList;

    //snip...other private members
    friend class CompanyIterator;
    friend class ConstCompanyIterator;
  public:

     // nested iterator classes
     class CompanyIterator : public std::iterator<std::forward_iterator_tag, Contact *> {

          friend class Company;
          // pair<>.first is the iterator obtain by calling begin()
          // pair<>.second is the end iterator
          std::stack< std::pair< std::list<Contact *>::iterator, 
                      std::list<Contact *>::iterator> > iters_stack;

          Contact *pCurrentContact;
          Company *pCompany; // This is the top level company which will be iterated.

        public:

          explicit CompanyIterator(Company &c);

          // Required forward iterator methods follow
          CompanyIterator();
          CompanyIterator(const CompanyIterator&);
          CompanyIterator& operator=(const CompanyIterator& other);
          Contact &operator*() const;
          Contact *operator->() const;
          CompanyIterator& operator++();
          CompanyIterator operator++(int);

          bool operator==(const CompanyIterator& x) const;
          bool operator!=(const CompanyIterator& x) const;
     };

     // nested iterator class
     class ConstCompanyIterator : public std::iterator<std::forward_iterator_tag, 
          const Contact *> {

          friend class Company;
          // We use CompanyIterator to implement ConstCompanyIteraor  
           CompanyIterator inner_iter; // fwd operations here,
                                      // using "const_cast<Company *>(this)->method()"
        public:

          explicit ConstCompanyIterator(const Company & dir);

          // This ctor will function as a cast operator, to convert a CompanyIterator
          // into a ConstCompanyIterator
          ConstCompanyIterator(const CompanyIterator &iter);

          // Required forward iterator methods follow
          ConstCompanyIterator();
          ConstCompanyIterator(const ConstCompanyIterator&);
          ConstCompanyIterator& operator=(const ConstCompanyIterator& other);

          const Contact &operator*() const;
          const Contact *operator->() const;

          ConstCompanyIterator& operator++();
          ConstCompanyIterator operator++(int);

          bool operator==(const ConstCompanyIterator& x) const;
          bool operator!=(const ConstCompanyIterator& x) const;
     };

    typedef CompanyIterator iterator;
    typedef ConstCompanyIterator const_iterator;

    iterator begin();
    iterator end();

    const_iterator begin() const;
    const_iterator end() const;

    // snip... other Company public methods
};

For the implementation of the forward iterator methods given above, see the Composite Iterator code on Github. Most of the implementation is in Directory.cpp. The github code is for composite pattern that models a file system. Class Directory is the composite. Class File is the leaf class. Class Node is the base component class.

The functor for find_if would look like

 FindIfFunctor {
      std::string name;
    public:
     FindIfFunctor(const std::string& n) : name(n) {} 
     bool operator()(const Contact& c) { return c.getName().compare(name); }
 }; 

Finally, the find_if code

 Company c;
 // snip... stuff gets added to company
 string someName("IBM");

 find_if(c.begin(), c.end(), FindIfFunctor(someName));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文