The Composite Design Patterns suggests the creation of an interface, that will let the Client treat a group of objects in a similar way as it is going to treat a single object, provided objects have methods or attributes in common.
Whenever we have a tree-like data structure, be it a file system, stacked resources, code, or anything composed from smaller parts, the Composite Pattern is the first design pattern to consider.
The Composite design pattern is a mechanism for treating individual objects and compositions of objects in a uniform manner and is classified under Structural Design Patterns as it provides one of the best methods to organize the class hierarchy.
- Child/Leaf element: Class representing elements which are placed at the bottom of the hierarchy tree. These elements do not spawn further elements.
- Composite Element: Class representing elements which are placed at any level of the hierarchy tree except for the bottom level. The class maintains the child objects by adding and removing them from the tree structure.
- Client: An entity or the module that wants to communicate with object or the group of objects.
Objective behind Composite design Pattern:
Consider an example of a program for a file management system:
- A file system is a tree structure that contains Branches representing Folders and Leaf nodes representing Files.
- Note that a folder object usually contains one or more file or folder objects and thus is a complex object where a file is a simple object.
- And as we know files and folders have many operations and attributes in common, such as moving and copying a file or a folder, listing file or folder attributes such as file name and size.
- It would be easier and more convenient to treat both file and folder objects uniformly by defining a File System Resource Interface.
That definition of File System Resources Interface in the above example is the main objective behind Composite Design Pattern. That is if a group of objects has methods or attributes in common provide an Interface so that client can treat them uniformly.
Let’s see how Leaf, Composite will look like in the following Python example:
Component is an abstract class that defines the common methods for leaf and composite:
from abc import abstractmethod class Component(): @abstractmethod def operation(self): pass
Leaf implements component’s abstract methods and these methods are the building block for the composite. We can create multiple leaf objects:
class Leaf(Component): """ Leaf """ def operation(self): pass
Composite contains a group of leaf objects, other than components’ methods, it will also have some helper methods to add or delete leaves from the group.
class Composite(Component): """ Composite Interface """ def __init__(self): self._children = set() def operation(self): for child in self._children: child.operation() def add(self, component): self._children.add(component) def remove(self, component): self._children.discard(component)
Full code will look like as below:
from abc import abstractmethod class Component(): @abstractmethod def operation(self): pass class Composite(Component): """ Composite Interface """ def __init__(self): self._children = set() def operation(self): for child in self._children: child.operation() #Method to add Leaves def add(self, component): self._children.add(component) #Method to remove Leaves def remove(self, component): self._children.discard(component) class Leaf(Component): """ Leaf """ def operation(self): pass #Driver Code def main(): leaf = Leaf() composite = Composite() composite.add(leaf) composite.operation() if __name__ == "__main__": main()
When to use Composite Pattern:
- First, When you want to represent part-whole hierarchies of objects.
This line simply means you can create a tree of objects that are made up of different parts, but that can be treated as a whole one big thing.
- Second, When 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.