Skip to content
kgleong edited this page Oct 18, 2015 · 4 revisions

Motivation

Clients sometimes do not need to burden of distinguishing between composite and primitive objects. Having knowledge of less classes can often lead to cleaner and simpler code.

The Composite design pattern is also useful when object relationships can be modeled by a tree hierarchy (i.e., parent and child objects).

A composite object is a container that contains child objects.

A primitive object is sometimes referred to as a leaf, and has no children.

The Composite pattern allows containers and child objects to appear identical to clients, leaving the details to the implementation of each class.

Code

Both Primitive and Composite objects are subclasses of a base Component class.

public abstract class Component {
    // Generic method that performs some work.
    public void performOperation();

    // Add and remove should only be called on composite objects.
    public boolean add(Component child) {
        throw new UnsupportedOperationException();
    }

    public boolean remove(Component child) {
        throw new UnsupportedOperationException();
    }
}

The add and remove operations are specifically for Composite classes to manage their children. Since Primitive objects do not have children, an exception is thrown by default.

It's the responsibility of Component instances with children to implement any children management operations.

The performOperation() method must be implemented by all Component objects.

public class Primitive extends Component {
    String mName;

    public Primitive(String name) {
        mName = name;
    }

    public void performOperation() {
        System.out.println(mName);
    }
}

Primitive instances usually use the performOperation() method to do some basic work.

For example, in a UI context, the primitive object might be an instance of a Line or Text class that contains a draw() method, which renders the line on the screen.

public class Composite extends Component {
    private List<Component> mChildren  = new ArrayList<>();

    public void performOperation() {
        for(Component child : mChildren) {
            child.performOperation();
        }
    }

    public boolean add(Component child) {
        return mChildren.add(child);
    }

    public boolean remove(Component child) {
        return mChildren.remove(child);
    }
}

Composite objects usually recursively pass calls to perform work down to their children.

In this way, the Composite design pattern allows a tree-like structure to be constructed, where all nodes are Component instances, where some nodes are leaves and others are parent nodes that contain children.

Usually calling performOperation() on a Composite instance sets off a recursive chain of calls down the tree in a top-down manner.

Using the same UI example mentioned above, a Picture class can consist of a number of lines, text, arcs, or other pictures.

Calling draw() on any Picture object will subsequently call draw() on any children and grandchildren, etc., rendering any primitive elements at any lower levels of the tree to the screen.

References

Clone this wiki locally