Avijeet Dash & Satyabrata Dash
Intent
Compose objects into tree structures to represent part-whole family
hierarchies. This pattern lets clients treat individual and compositions of
object uniformly.
In 30 Seconds
The catch is "achieving recursive composition by using a tree structure
which makes the client simple". A composite is a collection of objects.
Each object contains either a composite or a primitive object and the Composite
object represents a tree hierarchy with each object representing a node on it. A
node may have a branch i.e. another composite or it may just be a primitive
object. The key to the composite pattern is an abstract class that represents
both the primitives and their containers. This abstract class called ‘component’
declares all common operations for both composite and primitive (leaf nodes)
objects as well as all the child management operations. So client code
manipulates objects in the composition through the component interface.
Motivation
A primitive node doesn’t have any children where as a composite node has
children. In a simple example a composite node will return an Enumeration of
child nodes where as a primitive node will return nothing while trying to
retrieve the child nodes. So one group of thought suggests treating both of them
differently and keeping two interfaces. But Composite pattern insists on
retaining a uniform interface. So this makes the client simple. The client is
ignorant about the node structure and treats all the nodes in the same way. It
also makes it easier to add new components without worrying about their type.
Structure
- Click here https://www.ciol.com/images/composite_pattern.gif
to view diagram
Sample Code
/*
Various participants in this sample code are Acomponent, Leaf, Composite and
Client. Acomponent is the Component that defines the interface for objects in
composition. It also gives a default implementation for the child components.
Leaf has no children and here any attempt to add or remove a child from Leaf
will invoke Processsing Exception.
Composite represents a child node that can have branch nodes.
*/
Example-
import java.util.*;
// Processing Exception class
class ProcessingException extends Exception{
ProcessingException(){
super();
}
}
// Component
abstract class Acomponent{
Enumeration enum;
Vector vec;
Acomponent(){
vec=new Vector();
}
public void add(Object obj) throws ProcessingException{
vec.add(obj);
}
public void remove(Object obj) throws ProcessingException{
vec.remove(obj);
}
public Object getChild(int i) throws ProcessingException{
return vec.elementAt(i);
}
public Enumeration getChild(){
System.out.println(vec);
return vec.elements();
}
}
class Leaf extends Acomponent{
public void add(Object obj) throws ProcessingException{
throw new ProcessingException();
}
public void remove(Object obj) throws ProcessingException{
throw new ProcessingException();
}
public Object getChild(int i) throws ProcessingException{
throw new ProcessingException();
}
}
class Composite extends Acomponent{
//uses parent class operations
}
public class Client{
public static void main(String args<>) throws ProcessingException{
System.out.println("An example of Composite pattern");
Acomponent com=new Acomponent();
/* Write code to add a Composite object here.
*/
//Add child nodes
com.add(new Integer(1));
com.getChild();
com.add(new Integer(2));
com.getChild();
}
}
Complexities simplified
Explicit parent reference
Storing the parent component reference in a child simplifies the traversal
and management of a composite structure. It makes it easy to move up the
structure and deleting a component.
Where should the methods be defined?
It’s a long discussed and debatable topic. Should the methods be declared
in the Component class and let Composite and Leaf inherit them? But the critics
of this idea feel that Leaf unnecessarily inherits operation that is never meant
for it. It also involves a trade-off between safety and transparency. If we
define the operations in the Component class, then the same interface holds good
for both Leaf and Composite subclasses. It also gives transparency, because the
client needn’t bother about Leaf or Composite class. But if we define the
operations at a subclass level that gives more safety as any attempt to invoke
illegal operations can be caught during compile time.
So all these issues must be considered specific to an application.
Caching child information
When it is required to traverse the tree frequently to know about the
children, it’s better to cache them in the Composite class. It will improve
the performance a lot. We can also define a listener that will automatically
refresh the cache, when there is any update in the tree.
Choose a data structure to store components
We can choose a data structure out of many available in Java Collection API
like ArrayList, HashMap, Hashtable, LinkedList, Vector etc. Choosing a
particular data structure depends on requirement like efficiency, safety etc.
Vector and Hashtable are both thread-safe and hence slower in execution unlike
ArrayList or HashMap.
Also Known as and Related Patterns
The related patterns are Chain of Responsibility, Decorator, Flyweight,
Iterator and Visitor pattern.
The Chain of Responsibility pattern can be combined with the Composite
pattern by adding child to parent links so that children can get information
from an ancestor without having to know which ancestor the information came
from.
When Decorator is used with Composite, they have a common parent class. So
decorators will have to support the Component interface with common operations.
Flyweight also allows to share components but they don’t maintain a
reference to their parents.
We can use Iterator to traverse the tree in Composite.
Visitor encapsulates operations in a single class that would otherwise be
spread across multiple classes.
(The authors are senior developers at MindTree Consulting. They can
be reached at avijeetd@mindtree.com
and satyabrata_dash@mindtree.com).