【问题标题】:Composite pattern in C++C++ 中的复合模式
【发布时间】:2010-04-26 18:38:08
【问题描述】:

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

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

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

因此,Company 是 Compound 类型。

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

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

我希望我很清楚......

【问题讨论】:

  • 听起来你正在寻找一棵树。
  • 另外要在此处换行,您需要按两次空格键。有人可以编辑吗?
  • 这是真的...这是家庭作业,确实...

标签: c++ stl composite


【解决方案1】:

好吧,一种方法:

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

您所做的是要求每个节点找到您要查找的节点,而不关心它是什么类型的节点(叶子或其他)。然后每个节点检查自己,对于那些有子节点的节点,检查他们的子节点。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      您可以为 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
      };
      

      关于上面给出的前向迭代器方法的实现,请参见 Github 上的Composite Iterator 代码。大多数实现都在 Directory.cpp 中。 github 代码用于模拟文件系统的复合模式。类目录是复合的。 Class File 是叶类。 Class 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));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-11
        • 1970-01-01
        • 2022-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-08
        • 2020-09-08
        相关资源
        最近更新 更多