The Composite Design Pattern: Structured Object Management Made Easy
The Composite Design Pattern is part of the structural design patterns group and is particularly useful when a part-whole hierarchy needs to be represented. It is applied when a group of objects must be treated as a single object.
Application of the Composite Pattern
The Composite Design Pattern is used to create structures where all elements in the structure are treated the same way. A good example is a graphic composed of objects such as circles, lines, or triangles. When you color the graphic, for instance, in red, that color is applied to all objects. In this case, the graphic consists of different parts, but they all have the same functionality.
The Composite Pattern consists of the following components:
- Base Component: The base component defines an interface that all objects in the composition implement. The client program uses the base component to interact with the objects. This component can be an interface or an abstract class with common methods.
- Leaf: Leaf objects define the behavior of the elements within the composition. They are the building blocks of the composition and implement the base component. A leaf does not have references to other components.
- Composite: This component contains a group of leaf objects and implements the operations of the base component. It ensures that operations are applied to all contained leaves.
Implementation of the Composite Design Pattern
Here is an example of how the Composite Design Pattern can be applied to a graphical application:
1. Base Component:
The base component defines the methods that are implemented by leaves and the composite. A class Shape
could, for example, have a method draw(String fillColor)
to draw the shape with a given color.
package com.example.design.composite;
public interface Shape {
public void draw(String fillColor);
}
2. Leaf Objects:
Leaf objects such as triangles and circles implement the base component. These classes define how the respective shape is drawn.
package com.example.design.composite;
public class Triangle implements Shape {
@Override
public void draw(String fillColor) {
System.out.println("Drawing Triangle with color " + fillColor);
}
}
package com.example.design.composite;
public class Circle implements Shape {
@Override
public void draw(String fillColor) {
System.out.println("Drawing Circle with color " + fillColor);
}
}
3. Composite:
A composite object contains a collection of leaf objects. It provides methods for adding, removing, and clearing the group of leaves.
package com.example.design.composite;
import java.util.ArrayList;
import java.util.List;
public class Drawing implements Shape {
private List shapes = new ArrayList<>();
@Override
public void draw(String fillColor) {
for(Shape shape : shapes) {
shape.draw(fillColor);
}
}
public void add(Shape shape) {
shapes.add(shape);
}
public void remove(Shape shape) {
shapes.remove(shape);
}
public void clear() {
System.out.println("Clearing all shapes from drawing.");
shapes.clear();
}
}
Client Program
The following client program demonstrates how the Composite Design Pattern can be used:
package com.example.design.test;
import com.example.design.composite.Circle;
import com.example.design.composite.Drawing;
import com.example.design.composite.Shape;
import com.example.design.composite.Triangle;
public class TestCompositePattern {
public static void main(String[] args) {
Shape triangle1 = new Triangle();
Shape triangle2 = new Triangle();
Shape circle = new Circle();
Drawing drawing = new Drawing();
drawing.add(triangle1);
drawing.add(triangle2);
drawing.add(circle);
drawing.draw("Red");
drawing.clear();
drawing.add(triangle1);
drawing.add(circle);
drawing.draw("Green");
}
}
The output of the program shows how the Composite Pattern works in action:
Drawing Triangle with color Red
Drawing Triangle with color Red
Drawing Circle with color Red
Clearing all shapes from drawing.
Drawing Triangle with color Green
Drawing Circle with color Green
Important Points about the Composite Design Pattern
- The Composite Pattern should only be used when a group of objects needs to be treated as a single object.
- It is particularly useful for tree-like structures, where a composite can consist of several leaves.
By using this design pattern, flexibility in managing complex object structures is increased, and code maintainability is improved.