Composite Pattern Tutorial with Java Examples
Learn the Composite Design Pattern with easy Java source code examples as James Sugrue continues his design patterns tutorial series, Design Patterns Uncovered
Join the DZone community and get the full member experience.
Join For FreeToday's pattern is the Composite pattern, which comes into play when developing a system where a component could either be an individual object or a representation of a collection of objects.
Composite in the Real World
In programming, composites are used when dealing with tree structures. This itself is quite an abstract concept. One example of composite that you see daily is a menu system, where a menu bar has menu has many menu items, which themselves can have submenus. Anything that can be modelled as a tree structure can be considered an example of Composite, such as an organization chart.
Design Patterns Refcard
For a great overview of the most popular design patterns, DZone's Design Patterns Refcard is the best place to start.
The Composite Pattern
The Composite is known as a structural pattern,as it's used to form large object structures across many disparate objects. Thedefinition of Composite provided in the original Gang of Four book on DesignPatterns states:
Allow you to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
In it's simplest form, we can think of a composite as a collection of objects, where any one of these objects could itself be a composite, or a simple object. Let's take a look at the diagram definition before we go into more detail.
The Component interface defines the interface that all objects in the composed system need to use, whether they are leafs (simple objects) or compositions. However, this is usually implemented as an abstract class providing some default behaviour for the add, remove and getChild methods.
The Leaf has no children, and as such only needs to implement the operation method. The Composite needs to do more, as it also contains components. The composite will more than likely need to implement the operation method, which is considered as a Leaf-related operation. Sometimes this may not make sense for a composite to implement. Usually, the Composite will implement methods by delegating to the children. The Client simply uses the Component interface to manipulate the objects.
Would I Use This Pattern?
This pattern should be used when you want to represent objects in a hierachical fashion, or you need objects and composites to be treated uniformly.
Graphics frameworks are the most common use of this pattern. The base Graphic object provides the base class for all other graphic objects, such as Line, Rectangle, which provide their own implementations of the paint()/draw() method. The Composite pattern is frequently used for abstract syntax tree representations.
So How Does It Work In Java?
Graphics is a great example of how the Composite pattern works, so I'll use that here. First, we create an general interface for our graphics object. The main thing is that we have a paint method. Each graphic could be composed of other graphics too, so we'll need to provide a way to contain these objects.
//Component interface public interface Graphic{public void add(Graphic g);
public void remove(Graphic g);
public Graphic get(int index);
public void paint();}
Next, we'll implement this interface for CompositeGraphic objects. The key point to note here is that it's paint method delegates the painting to children objects:
//Composite public class CompositeGraphic implements Graphic{private List<Graphic> children = new ArrayList<Graphic>();
public void paint(){//run the paint operation for each child for(Graphic g: children){g.paint();}}
public void add(Graphic g){children.add(g);}
public void remove(Graphic g){if(children.contains(g)){children.remove(g);}}
public Graphic get(int index){if(index < children.size()){return children.get(index);}}}
The leaf, in this case SimpleGraphic, cannot contain other graphics, so it doesn't need to implement the list operations. The most important this is that it provides a concrete implementation of the paint() method:
//Leafpublic class SimpleGraphic implements Graphic{public void paint(){//run the paint operation}/** * Because we have no children, these operations will do nothing **/public void add(Graphic g){//unsupported operation}public void remove(Graphic g){//unsupported operation}public void get(int index){//unsupported operation}}
And finally, for the client, things couldn't be easier. All they need to do is to know about the interface, and all the work is done for them:
//Client.public class GraphicsClient{/** * Given a graphics context, client can just call paint, without worrying if this is a composite or leaf **/
public void paint(Graphics g){g.paint();}}
Watch Out for the Downsides
The Composite pattern does one thing really well, and that is that it allows you to treat both nodes and leafs in the same way. However, by providing this flexibility and transparency, you're choosing a trade-off on the Single Responsibility principle. This is not necessarily a bad thing, but it's something that you should keep in mind.
Your system could also be overly general, and it can be difficult to find objects. Taking this into account, the pattern probably isn't ideal to use as a data structure. In cases where the ordering of child nodes is important, you will need to add in extra functionality, perhaps utilizing the Iterator pattern.
Next Up
In the next article, I'll introduce the Flyweight design pattern.
Enjoy the Whole "Design Patterns Uncovered" Series:
Creational Patterns
- Learn The Abstract Factory Pattern
- Learn The Builder Pattern
- Learn The Factory Method Pattern
- Learn The Prototype Pattern
- Learn The Singleton Pattern
Structural Patterns
- Learn The Adapter Pattern
- Learn The Bridge Pattern
- Learn The Composite Pattern
- Learn The Decorator Pattern
- Learn The Facade Pattern
- Learn The Flyweight Pattern
- Learn The Proxy Pattern
Behavioral Patterns
- Learn The Chain of Responsibility Pattern
- Learn The Command Pattern
- Learn The Interpreter Pattern
- Learn The Iterator Pattern
- Learn The Mediator Pattern
- Learn The Memento Pattern
- Learn The Observer Pattern
- Learn The State Pattern
- Learn The Strategy Pattern
- Learn The Template Method Pattern
- Learn The Visitor Pattern
Opinions expressed by DZone contributors are their own.
Comments