Composite Pattern
Composite is a structural design pattern that lets you compose objects into tree structures to represent whole-part hierarchies. We will explore it using a drawing application!
Note
This reading is based on the ShapeDrawingApp
.
Problem¶
We want our drawing editor to support grouping and ungrouping operations so that a number of 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/Cons
- Pros: simple
- Cons: cannot support nested groups
Solution 2¶
Introduce a new class ShapeGroup
to manage a group of shapes.
Pros/Cons
- 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 together into a single entity which behaves in the same way as a single shape.
Note
Download the updated ShapeDrawingApp
with a working grouping/ungrouping feature.
The Pattern¶
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 component.
- Typically implements operations of
Component
simply by calling the same operation for each of its constituent components.
- Concrete Component (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.