Item 38: Model "has-a" or "is-implemented-in-terms-of" through composition
Concept
Composition (layering/containment) means having an object of one type as a data member of another. In the application domain, composition models "has-a" relationships (a Person has-a name, has-an address). In the implementation domain, composition models "is-implemented-in-terms-of" (a Set might be implemented using a std::list internally). Composition is fundamentally different from is-a (public inheritance) and should be used when the relationship between types doesn't satisfy the Liskov Substitution Principle.
Code Example
#include <string>
#include <list>
// "has-a" in the application domain
class Person {
private:
std::string name_; // Person has-a name
std::string address_; // Person has-a address
};
// "is-implemented-in-terms-of" in the implementation domain
template <typename T>
class Set {
public:
void insert(const T& item) {
if (!contains(item))
data_.push_back(item);
}
bool contains(const T& item) const;
void remove(const T& item);
private:
std::list<T> data_; // Set is-implemented-in-terms-of list
// NOT "Set is-a list" — a list allows duplicates, a Set does not
};
Things to Remember
- Composition has meanings completely different from that of public inheritance.
- In the application domain, composition means "has-a." In the implementation domain, it means "is-implemented-in-terms-of."