Composite Design Pattern

Pattern: Composite is a structural design pattern that lets you compose objects into tree structures to represent whole-part hierarchies.

Suppose we have created a simple shape drawing application that can draw basic geometric shapes. Suppose, further, the following is a partial class diagram for this system.

Problem: We want our drawing editor to support grouping and ungrouping operations so that several shapes can be collected together and treated as a single entity.

Solution 1: We could add a group member field into AbstractShape to indicate which group each shape belongs to (using the number -1 to indicate that the object is not in any group).

  • Pros: simple
  • Cons: cannot support nested groups

Solution 2: Introduce a new class ShapeGroup to manage a group of shapes.

  • Pros: Supports nested groups
  • Cons: You would have to treat primitives (shapes) and container classes (shapeGroups) differently, making the application more complex than necessary.

Solution 3: Implement the ShapeGroup class as a subclass of Shape.

The ShapeGroup class provides a means by which several shapes can be grouped into a single entity that behaves in the same way as a single shape.

The composite design pattern provides a means of grouping together several objects of type T such that the grouped object is also of type T.

In the diagram above

  • Component:
    • Declares the abstraction for objects in the composition.
    • Could optionally implement default behavior common to all subclasses.
  • Composite:
    • Represents an aggregate object (collection of components).
    • Usually has methods to add/remove components.
    • Typically implements operations of Component simply by calling the same operation for each of its constituent components.
  • ConcreteComponent (a.k.a Leaf)
    • Defines behavior for primitive objects in the composition.

When to use this pattern?

  • Need to manipulate a hierarchical collection of "primitive" and "aggregate" objects.
  • Need to process (treat) primitive objects the same way as aggregate objects.
  • Examples: file/folder hierarchies, organizational charts, tables of contents, parsing structured documents like XML/HTML, etc.

Advantage: Clients typically only need to interact with the Component interface; they would be unaware if they're dealing with a composite or a leaf object. This hides the complexity of the data structure from the outside world.