Композитный паттерн в C ++ - PullRequest
1 голос
/ 26 апреля 2010

Мне нужно работать с приложением на C ++, похожим на телефонную книгу: класс Agenda со списком контактов STL. Что касается иерархии контактов, существует базовый класс с именем Contact (абстрактный) и производный занятия Friend и знакомство (виды контактов).

Эти классы имеют, например, виртуальный метод getName, который возвращает имя контакта.

Теперь я должен реализовать составной шаблон , добавив другой тип контакта, Company (производный от Contact), который также содержит коллекцию контактов (также список STL), которые могут быть типа «лист» (друзья или знакомые), или они также могут быть компаниями.

Следовательно, Компания является типом Соединения.

Вопрос заключается в следующем: как и где я могу реализовать STL find_if для поиска контакта с данным именем (с помощью функции getName или предложить мне что-то еще) как в контакте типа «лист», так и в контакте. внутри коллекции компании?

Другими словами, как мне пройти по дереву, чтобы найти там возможные совпадения, используя унифицированное определение функции?

Надеюсь, я достаточно ясно ...

Ответы [ 3 ]

2 голосов
/ 26 апреля 2010

Ну, один из способов сделать это:

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

Что вы делаете, так это просите каждый узел найти тот, который вы ищете, не заботясь о том, какой это тип узла (конечный или другой). Затем каждый узел проверяет себя, а для тех, у кого есть дочерние узлы, своих потомков.

1 голос
/ 26 апреля 2010

Список является неправильным типом для большого типа контактов, поскольку у вас может быть O (N), чтобы найти последний контакт или даже не найти контакт.
Я предлагаю вам использовать хеш-карту (unordered_map из boost / tr1) или обычную карту, чтобы вы могли найти их по идентификатору или по их имени с помощью ключа.
Также звучит так, будто компания должна быть просто деревом контактов.
Вы можете найти дерево реализации здесь .
Вы переходите через дерево, чтобы найти нужный вам узел.

0 голосов
/ 07 января 2014

"Теперь я должен внедрить шаблон Composite, добавив другой тип контакта, Company (производный от Contact), который также содержит коллекцию контактов (в том числе список STL), которые могут быть любым из" листьев " тип (Друзья или знакомые), или они могут быть также компаниями "

Вы можете создать stl-совместимый составной итератор для 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
};

Для реализации методов прямого итератора, приведенных выше, см. Код Composite Iterator на Github. Большая часть реализации находится в Directory.cpp. Код GitHub для составного шаблона, который моделирует файловую систему. Класс Directory является составным. Файл класса является листовым классом. Класс 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));
...