Intent
It is belongs to structural design patterns catalog.Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Explanation
Real world example
Every sentence is composed of words which are in turn composed of characters. Each of these objects is printable and they can have something printed before or after them like sentence always ends with full stop and word always has space before itIn plain words
Composite pattern lets clients treat the individual objects in a uniform manner.Wikipedia says
In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes that a group of objects is to be treated in the same way as a single instance of an object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.Structure
Participants
1. Component- declares the interface for objects in the composition.
- implements default behavior for the interface common to all classes,as appropriate.
- declares an interface for accessing and managing its child components.
- (optional) defines an interface for accessing a component's parent in the recursive structure, and implements it if that's appropriate.
- represents leaf objects in the composition. A leaf has no children.
- defines behavior for primitive objects in the composition.
- defines behavior for components having children.
- stores child components.
- implements child-related operations in the Component interface.
- manipulates objects in the composition through the Component interface.
Collaborations
- Clients use the Component class interface to interact with objects in the composite structure. If the recipient is a Leaf, then the request is handled directly. If the recipient is a Composite, then it usually forwards requests to its child components, possibly performing additional operations before and/or after forwarding.
Source Code (Example 1)
Taking our sentence example from above. Here we have the base class and different printable typespublic abstract class LetterComposite {
private List<LetterComposite> children = new ArrayList<>();
public void add(LetterComposite letter) {
children.add(letter);
}
public int count() {
return children.size();
}
protected void printThisBefore() {}
protected void printThisAfter() {}
public void print() {
printThisBefore();
for (LetterComposite letter : children) {
letter.print();
}
printThisAfter();
}
}
public class Letter extends LetterComposite {
private char c;
public Letter(char c) {
this.c = c;
}
@Override
protected void printThisBefore() {
System.out.print(c);
}
}
public class Word extends LetterComposite {
public Word(List<Letter> letters) {
for (Letter l : letters) {
this.add(l);
}
}
@Override
protected void printThisBefore() {
System.out.print(" ");
}
}
public class Sentence extends LetterComposite {
public Sentence(List<Word> words) {
for (Word w : words) {
this.add(w);
}
}
@Override
protected void printThisAfter() {
System.out.print(".");
}
}
Then we have a messenger to carry messages
public class Messenger {
LetterComposite messageFromOrcs() {
List<Word> words = new ArrayList<>();
words.add(new Word(Arrays.asList(new Letter('W'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
words.add(new Word(Arrays.asList(new Letter('a'))));
words.add(new Word(Arrays.asList(new Letter('w'), new Letter('h'), new Letter('i'), new Letter('p'))));
words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter('r'), new Letter('e'))));
words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
words.add(new Word(Arrays.asList(new Letter('a'))));
words.add(new Word(Arrays.asList(new Letter('w'), new Letter('a'), new Letter('y'))));
return new Sentence(words);
}
LetterComposite messageFromElves() {
List<Word> words = new ArrayList<>();
words.add(new Word(Arrays.asList(new Letter('M'), new Letter('u'), new Letter('c'), new Letter('h'))));
words.add(new Word(Arrays.asList(new Letter('w'), new Letter('i'), new Letter('n'), new Letter('d'))));
words.add(new Word(Arrays.asList(new Letter('p'), new Letter('o'), new Letter('u'), new Letter('r'), new Letter('s'))));
words.add(new Word(Arrays.asList(new Letter('f'), new Letter('r'), new Letter('o'), new Letter('m'))));
words.add(new Word(Arrays.asList(new Letter('y'), new Letter('o'), new Letter('u'), new Letter('r'))));
words.add(new Word(Arrays.asList(new Letter('m'), new Letter('o'), new Letter('u'), new Letter('t'), new Letter('h'))));
return new Sentence(words);
}
}
And then it can be used as
LetterComposite orcMessage = new Messenger().messageFromOrcs();
orcMessage.print(); // Where there is a whip there is a way.
LetterComposite elfMessage = new Messenger().messageFromElves();
elfMessage.print(); // Much wind pours from your mouth.
Source Code (Example 2)
Step 1 : Create an Employee interface that will be treated as a component.
/ this is the Employee interface i.e. Component.
public interface Employee {
public int getId();
public String getName();
public double getSalary();
public void print();
public void add(Employee employee);
public void remove(Employee employee);
public Employee getChild(int i);
}// End of the Employee interface.
Step 2 : Create a BankManager class that will be treated as a Composite and implements Employee interface.
// this is the BankManager class i.e. Composite.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class BankManager implements Employee {
private int id;
private String name;
private double salary;
public BankManager(int id,String name,double salary) {
this.id=id;
this.name = name;
this.salary = salary;
}
List<Employee> employees = new ArrayList<Employee>();
@Override
public void add(Employee employee) {
employees.add(employee);
}
@Override
public Employee getChild(int i) {
return employees.get(i);
}
@Override
public void remove(Employee employee) {
employees.remove(employee);
}
@Override
public int getId() {
return id;
}
@Override
public String getName() {
return name;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void print() {
System.out.println("==========================");
System.out.println("Id ="+getId());
System.out.println("Name ="+getName());
System.out.println("Salary ="+getSalary());
System.out.println("==========================");
Iterator<Employee> it = employees.iterator();
while(it.hasNext()) {
Employee employee = it.next();
employee.print();
}
}
}// End of the BankManager class.
Step 3 : Create a Cashier class that will be treated as a leaf and it will implement to the Employee interface.
public class Cashier implements Employee{
/*
In this class,there are many methods which are not applicable to cashier because
it is a leaf node.
*/
private int id;
private String name;
private double salary;
public Cashier(int id,String name,double salary) {
this.id=id;
this.name = name;
this.salary = salary;
}
@Override
public void add(Employee employee) {
//this is leaf node so this method is not applicable to this class.
}
@Override
public Employee getChild(int i) {
//this is leaf node so this method is not applicable to this class.
return null;
}
@Override
public int getId() {
// TODO Auto-generated method stub
return id;
}
@Override
public String getName() {
return name;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void print() {
System.out.println("==========================");
System.out.println("Id ="+getId());
System.out.println("Name ="+getName());
System.out.println("Salary ="+getSalary());
System.out.println("==========================");
}
@Override
public void remove(Employee employee) {
//this is leaf node so this method is not applicable to this class.
}
}
Step 4 : Create a Accountant class that will also be treated as a leaf and it will implement to the Employee interface.
public class Accountant implements Employee{
/*
In this class,there are many methods which are not applicable to cashier because
it is a leaf node.
*/
private int id;
private String name;
private double salary;
public Accountant(int id,String name,double salary) {
this.id=id;
this.name = name;
this.salary = salary;
}
@Override
public void add(Employee employee) {
//this is leaf node so this method is not applicable to this class.
}
@Override
public Employee getChild(int i) {
//this is leaf node so this method is not applicable to this class.
return null;
}
@Override
public int getId() {
// TODO Auto-generated method stub
return id;
}
@Override
public String getName() {
return name;
}
@Override
public double getSalary() {
return salary;
}
@Override
public void print() {
System.out.println("=========================");
System.out.println("Id ="+getId());
System.out.println("Name ="+getName());
System.out.println("Salary ="+getSalary());
System.out.println("=========================");
}
@Override
public void remove(Employee employee) {
//this is leaf node so this method is not applicable to this class.
}
}
Step 5 : Create a CompositePatternDemo class that will also be treated as a Client and ii will use the Employee interface.
public class CompositePatternDemo {
public static void main(String args[]){
Employee emp1=new Cashier(101,"Sohan Kumar", 20000.0);
Employee emp2=new Cashier(102,"Mohan Kumar", 25000.0);
Employee emp3=new Accountant(103,"Seema Mahiwal", 30000.0);
Employee manager1=new BankManager(100,"Ashwani Rajput",100000.0);
manager1.add(emp1);
manager1.add(emp2);
manager1.add(emp3);
manager1.print();
}
}
Applicability
Use the Composite pattern when
- you want to represent part-whole hierarchies of objects
- you want clients to be able to ignore the difference between compositions of objects and individual objects. Clients will treat all objects in the composite structure uniformly