-
Notifications
You must be signed in to change notification settings - Fork 3
Composite
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.
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.