Also known as Tree

Composite

Intent

Composite is a structural design pattern that let you compose objects into tree structures and allow clients to work with these structures as if they were individual objects.

Problem

The composite pattern makes sense only when your business model can be represented as a tree.

For instance, you have two objects: Product and Box. The Box can contain several Products and a number of smaller Boxes inside. These little Boxes can also hold inside some Products or even smaller Boxes and so on.

Now, imagine that your Products and Boxes can be a part of order. How hard can it be to calculate the order total? You just take a large Box, unwrap it and see what's inside: ProductA, ProductB, oh, another Box, let's see what inside... Before too long, you'll end up in a pile of duct tape and cardboard still trying to sum-up the price.

Isn't there a better way?

Solution

The Composite pattern suggests treating all different Products and Boxes through a common interface that has a method getPrice().

In Products, it will just return the product's price. But Boxes will get much more interesting behavior. A Box will go over its content and ask every item its price. Naturally, if an item was a product, it will return the price right away. But if that was a smaller box, it will also start looking over its items asking for the price until it can return the total. Once the subtotal is calculated, a Box can even add some extra to the full price, like a packaging cost.

Now, probably the greatest benefit of this approach is that you don't need to care much about the concrete objects that make a tree. Whether it's a single Product or sophisticated Box, you treat it through a generic interface. And the structure handles passing the requests down by itself.

Real-World Analogy

Military structure

Armies of most countries look like composite trees. On the lowest level, there are soldiers. They are grouped into squads. Several squads make a platoon. Platoons make a division. And finally, several divisions make an army.

Orders are given at the top of the hierarchy and passed down at each level until every soldier knows what needs to be done.

Structure

Composite pattern structure
  1. Component defines the common interface for both simple and complex elements of a tree.

  2. Leaf is a basic element of a tree that does not have children.

    Since they don't have anyone to delegate to, leaves often do most of the real job.

  3. Container (aka Composite) is an element that has children: Leaves or other Containers. Containers don't know the type of their children since they work with them via Component interface.

    Upon receiving a request, Containers delegate the work to their children, then process and sum-up the results before return it to Client.

  4. Client uses all tree elements only through the Component interface.

    Thus, the Client does not care whether it deals with a simple Leaf or a complex Container.

Pseudocode

In this example, the Composite pattern helps to implement stacking geometric shapes.

The CompoundGraphic is a container that can consist of any number of sub-shapes, including other compound shapes. The compound shape has the same methods as a simple shape. But instead of doing the actual work, it delegates requests to its child shapes that recursively traverse over all immediate and distant sub-shapes. The container then sums up the results and returns it to the client.

The client works with all shapes through the interface, common to all types of shapes. This way the client code can work with very complex structures without coupling to the concrete classes of tree elements.

// Common interface for all components.
interface Graphic is
    method move(x, y)
    method draw()

// Simple component.
class Dot implements Graphic is
    field x, y

    constructor Circle(x, y) { ... }

    method move(x, y) is
        this.x += x, this.y += y

    method draw() is
        Draw a dot at X and Y.

// Components could extend other components.
class Circle extends Dot is
    field radius

    constructor Circle(x, y, radius) { ... }

    method move(x, y) is
        this.x = x, this.y = y

    method draw() is
        Draw a circle at X and Y and radius R.

// The composite component includes methods to add/remove child components. It
// tries to delegates to its children all operations defined in the
// component interface.
class CompoundGraphic implements Graphic is
    field children: array of Graphic

    method add(child: Graphic) is
        Add child to children array.

    method remove(child: Graphic) is
        Remove child to children array.

    method move(x, y) is
        For each child: child.move(x, y)

    method draw() is
        Go over all children and calculate bounding rectangle.
        Draw a dotted box using calculated values.
        Draw each child.


// Application can operate with specific components or whole groups.
class ImageEditor is
    method load() is
        all = new CompoundGraphic()
        all.add(new Dot(1, 2))
        all.add(new Circle(5, 3, 10))
        // ...

    method groupSelected(components: array of Graphic) is
        group = new CompoundGraphic()
        group.add(components)
        all.remove(components)
        all.add(group)
        // All components will be drawn.
        all.draw()

Applicability

When you have to implement a tree-like structure that has simple elements and containers.

The Composite pattern offers two basic elements: simple leaves and complex containers that store other leaves or containers, and so on. Pattern forces the containers to work with all child elements through the common interface, which allows running operations recursively over the whole tree structure.

When Clients should treat simple and complex elements uniformly.

Thanks to the common interface between leaves and containers, Client code does not have to care about the type of object it works with.

How to Implement

  1. Make sure that your business logic can be represented as a tree structure. Try to break it into simple elements and containers. Remember that containers can contain both simple elements and other containers.

  2. Describe a common interface for all Components. It should contain operations that make sense for both simple and complex components.

  3. Create a Leaf class that represents simple components. By the way, a program could have multiple leaf classes.

  4. Create a Container class that has an array field for storing sub-components. It should be able to store both Leaves and Containers, so make sure it's defined with a Component type.

    While implementing the Component interface methods, remember that Container should be delegating most of its work to subcomponents.

  5. Finally, implement methods to add/remove child elements to the Container.

    Keep in mind, that these operations could also be put into the Component interface. It will violate the Interface Segregation Principle because these methods will be empty in Leaf class. But on the other hand, all of the tree components will become truly equal for the Client's standpoint.

Pros and Cons

  • Simplifies the client code that has to interact with a complex tree structure.
  • Makes easier adding new component types.
  • Creates a too general class design.

Relations with Other Patterns

  • Builder can be used to build a complex Composite tree step by step.

  • Chain of Responsibility is often applied in conjunction with Composite. In this case, a component's parent can act as its successor.

  • Iterators can be used for traversing Composite trees.

  • Visitor can apply an operation over entire Composite tree.

  • Flyweight is often combined with Composite to implement shared leaf nodes and save RAM.

  • Composite and Decorator have similar structure diagrams since they both rely on recursive composition to organize an open-ended number of objects.

    Decorator can be viewed as a degenerate Composite with only one component. However, Decorator adds additional responsibilities to the object while Composite just "summs up" of the same behavior executed over its children.

    But they can also cooperate: Composite can use Decorator to change behavior of the tree components.

  • Designs that make heavy use of the Composite and Decorator patterns often can benefit from Prototype as well. It would allow to clone complex structures, instead of re-constructing them from scratch.

Implementations in Different Programming Languages

Java