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 con开发者_运维技巧tacts 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...
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.
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.
"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));
精彩评论