8.2. Composite Pattern: Parents and Children

[ fromfile: children.xml id: children ]

According to [Gamma95], the Composite pattern is intended to facilitate building complex (composite) objects from simpler (component) parts by representing the part-whole hierarchies as tree-like structures. This must be done in such a way that clients do not need to distinguish between simple parts and more complex parts that are made up of (i.e., contain) simpler parts.

Figure 8.2.  Composite Pattern

Composite Pattern

Figure 8.2 describes the Composite pattern. In this diagram, there are two distinct classes for describing two roles.

Many Qt classes use the Composite pattern: QObject, QWidget, QTreeWidgetItem, QDomNode, QHelpContentItem, QResource. The Composite pattern can be found in just about any tree-based structure.

Figure 8.3.  QObject: Composite and Component

QObject: Composite and Component

In Figure 8.3, you can see that QObject is both composite and component. You can express the whole-part relationship as a parent-child relationship between QObjects. The highest level (i.e., most "composite") QObject in such a tree (i.e., the root of the tree) will have children but no parent. The simplest QObjects (i.e., the leaf nodes of this tree) each have a parent but no children. Client code can recursively deal with each node of the tree.

For an example of how the Composite pattern might be used, let's look at Suffolk University. In 1906 the founder, Gleason Archer, decided to start teaching the principles of law to a small group of tradesmen who wanted to become lawyers. He was assisted by one secretary and, after a while, a few instructors. The organizational chart for this new school was quite simple: a single office consisting of several employees with various tasks. As the enterprise grew, the chart gradually became more complex with the addition of new offices and departments. Today, more than a hundred years later, the Law School has been joined with a College of Arts and Sciences, a School of Management, a School of Art and Design, campuses abroad, and many specialized offices so that the organizational chart has become quite complex and promises to become more so. Figure 8.4 shows an abbreviated and simplified subchart of today's Suffolk University.

Figure 8.4. Suffolk University Organizational Chart

Suffolk University Organizational Chart

Each box in this chart is a component. It may be a composite and have subcomponents which, in turn, may be composite or simple components. For example, the PresidentOffice has individual employees (e.g., the President and his assistants) and suboffices (e.g., DiversityServices). Each leaf of this tree is an individual employee of the organization.

You can use the Composite pattern to model this structure. Each node of the tree can be represented by an object of type OrgUnit.

class OrgUnit : public QObject {
  public:
    QString getName();
    double getSalary();
  private:
    QString m_Name;
    double m_Salary;
};

The QObject public interface enables you to build up a tree-like representation of the organization with code that instantiates an OrgUnit and then calls setParent() to add it to the appropriate child list.

For each OrgUnit pointer ouptr in the tree, initialize its m_Salary data member as follows:

You can implement the getSalary() method like this:

double OrgUnit::getSalary() {
  QList<OrgUnit*> childlst = findChildren<OrgUnit*>();
  double salaryTotal(m_Salary);
  if(!childlst.isEmpty())
    foreach(OrgUnit* ouptr, childlst)
      salaryTotal += ouptr->getSalary();
  return salaryTotal;
}

A call to getSalary() from any particular node returns the total salary for the part of the university represented by the subtree whose root is that node. For example, if ouptr points to University, ouptr->getSalary() returns the total salary for the entire university. If ouptr points to EnglishDpt, then ouptr->getSalary() returns the total salary for the English Department. If ouptr points to ProfE, ouptr->getSalary() simply returns ProfE's individual salary.