简体   繁体   English

C ++中的复合模式

[英]Composite pattern in C++

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). 我必须使用类似于电话簿的C ++应用程序:具有STL联系人列表的Agenda类。关于联系人层次结构,有一个名为Contact(抽象的)的基类,而派生类Friend和熟人(联系方式)。

These classes have,for instance, a virtual method called getName,which returns the name of the contact. 例如,这些类具有一个名为getName的虚拟方法,该方法返回联系人的姓名。

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. 现在,我必须通过添加另一种类型的联系人Company(从Contact派生)来实现Composite模式 ,该类型也包含Contacts的集合(也包括STL列表),可以是“叶子”类型(Friends或熟人),也可以是公司。

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? 问题是:如何在哪里以及在哪里使用STL find_if来在“叶子”类型的Contact和Company集合内搜索具有给定名称的联系人(通过getName函数或建议我其他方式)?

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... 我希望我很清楚...

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. 然后,每个节点检查自己,对于具有子节点的节点,将检查其子节点。

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. 对于大型联系人,列表类型错误,因为您可能有一个O(N)来查找最后一个联系人,甚至找不到任何联系人。
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. 我建议您使用哈希映射(boost / tr1中的unordered_map)或常规映射,这样您就可以使用ID通过ID或名称找到它们。
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. 您可以通过树进行遍历以找到所需的节点。

"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" “现在,我必须通过添加另一种类型的联系人Company(从Contact派生)来实现Composite模式,该类型也包含Contacts的集合(也包括STL列表),可以是“ leaf”类型(Friends或熟人),也可以是公司”

You could create a stl-compatible composite iterator for Company. 您可以为Company创建一个与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
};

For the implementation of the forward iterator methods given above, see the Composite Iterator code on Github. 有关上面给出的正向迭代器方法的实现,请参见Github上的Composite Iterator代码。 Most of the implementation is in Directory.cpp. 大多数实现在Directory.cpp中。 The github code is for composite pattern that models a file system. github代码用于建模文件系统的复合模式。 Class Directory is the composite. 类目录是组合目录。 Class File is the leaf class. 类文件是叶类。 Class Node is the base component class. 类Node是基础组件类。

The functor for find_if would look like find_if的函子看起来像

 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 最后,find_if代码

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM