Summary
Pattern Name | Composite Pattern |
Pattern Type | Structural Pattern |
Scope | Object |
Tagline | Handle list of objects (compositions) of the same interface together |
Use cases | When objects of the same type need to be handled together and the handling class needs to implement the same interface |
Related Patterns | Decorator Iterator Flyweight Visitor |
Difficulty Level | Easy |
Implementations |
Definition
When there is a bunch of classes that are of the same type (implement the same interface), and we need to use them as composition (not as individual objects), we can use Composite pattern.
Composite pattern helps to use the classes in a composition, so that the client can use the composition and individual classes can be treated in the same way.
We can think of the composition as depicted in the diagram below. Each composition consists of one or more individual objects or compositions.
Use Cases
Here are the use cases of Composite pattern:
- When we want the client to treat individual objects and compositions(groups) of objects the same way.
- When we need to handle a list of items(or component tree), and maintain the order/sequence of the items.
- Where there are concerns about memory usage or performance while handling a list of objects (of the same type).
Implementation
Composite pattern implementation has 3 parts.
- Component: this is the interface that all classes implement so that the composition of classes can work.
- Leaf: these are the individual classes.
- Composite: this class implements the same interface as the leaf, and handles the composition/leaf/group of individual classes.
Use the following steps and criteria to implement Composite pattern.
- Create an interface, that the leaf classes and composite class will implement.
- Implement the interface for all the Leaf classes. Leaf classes do not have any reference to other classes.
- Create a composite class.
- Maintain a list of Leaf objects in the composite class.
- Implement methods to add and remove Leaf objects in the composite class.
- Implement the base interface for composite class.
- In the composite class, the implemented methods will call the methods of all Leaf objects in the list (in loops).
- In the client add/remove the Leaf object in the list of composite classes, then call the functions of the composite class when required.
Examples
Example #1: Transport Composite List
Let’s consider a transport system in an application. Take a look at the class diagram first:
Here we have different transport available – car, bike, plane. We will use the composite pattern (using TransportGroup class) to handle a list/group of transports.
Transport Interface
Interface for all transports, both individual and group.
// Transport interface
interface Transport
function start()
function operate()
function stop()
end interface
Transport Individual Classes
Individual transport classes. All these classes implement the Transport interface.
// Bike class
class Bike implements Transport
function start()
print "Starting Bike..."
end function
function operate()
print "Riding Bike"
end function
function stop()
print "Stopping Bike..."
end function
end class
// Plane class
class Plane implements Transport
function start()
print "Starting Plane..."
end function
function operate()
print "Flying Plane"
end function
function stop()
print "Stopping Plane..."
end function
end class
// Car class
class Car implements Transport
function start()
print "Starting Car..."
end function
function operate()
print "Driving Car"
end function
function stop()
print "Stopping Car..."
end function
end class
Composite Class
A composite class for groups of transport. This implements the Transport interface and holds an array of transport objects to maintain a list.
For implementing the Transport in all the function definitions, this composite class performs the operations on the list.
class TransportGroup implements Transport
var transportList: Transport[] // Maintain a list of Transport Leaf classes
// Override start of Transport interface
function start()
loop transportList as transport
transport.start()
end loop
end function
// Override operate of Transport interface
function operate()
loop transportList as transport
transport.operate()
end loop
end function
// Override stop of Transport interface
function stop()
loop transportList as transport
transport.stop()
end loop
end function
function addTransport(Transport transport)
// Add object to list
transportList.add(transport)
end function
function removeTransport(Transport transport) {
// Remove object from list
transportList.remove(transport)
end function
end class
Demo
Client can use the individual Transport classes and the composite class objects the same way. The client does not know any difference between those two.
var bike: Bike = new Bike()
var plane: Plane = new Plane()
var car: Car = new Car()
var secondCar: Car = new Car()
TransportGroup transports = new TransportGroup()
// Add 4 transports
transports.addTransport(bike)
transports.addTransport(plane)
transports.addTransport(car)
transports.addTransport(secondCar)
// Perform operation of the list of 4 transports
transports.start()
transports.operate()
transports.stop()
// Remove plane and perform operations on other transports
transports.removeTransport(plane)
transports.start()
transports.operate()
transports.stop()
Output
The output of the demo above will be like below.
-----------------Output with 4 transports------------------
Starting Bike...
Starting Plane...
Starting Car...
Starting Car...
Riding Bike
Flying Plane
Driving Car
Driving Car
Stopping Bike...
Stopping Plane...
Stopping Car...
Stopping Car...
-----------------Output when plane is removed------------------
Starting Bike...
Starting Car...
Starting Car...
Riding Bike
Driving Car
Driving Car
Stopping Bike...
Stopping Car...
Stopping Car...
Code Implementations
Use the following links to check Composite pattern implementation in specific programming languages.