Composite Design Pattern Using Python

Introduction

 
A composite design pattern is a structural design pattern. It allows a developer to create multiple nested objects of the same type to complete one single system hierarchy.
 
Players in this pattern:
  • Component: this player defines a base contract with a composite class to allow create nested objects.
  • Composite: this player, is one who will implement the contract defined by component.
  • Client: this player with the help of a composite player. It will complete the system hierarchy for a particular requirement
We will see with an example.
 
Requirement
 
Build a smart city with smart block features.
 
We will define 3 player 
  • AbstractBlock – Component
  • Block – Composite
  • Client
We will build an Abstract block with Add, Remove block features. If we want we can implement Add, Remove features explicitly. In my case, I am using List, by default I will be having Add(append), and Remove features available for adding/removing blocks.
  1. from abc import abstractmethod  
  2.   
  3. class AbstractBlock:  
  4.     name:str  
  5.     size:any  
  6.     sub_blocks=[]  
  7.  
  8.     @abstractmethod  
  9.     def build_block(self):  
  10.         pass  
Now implement a Composite object, i.e. Block by implementing/inheriting component i.e. in our code AbstractBlock 
  1. from abstractBlock import AbstractBlock  
  2.   
  3. class Block(AbstractBlock):  
  4.   
  5.    def __init__(self):  
  6.        self.sub_blocks =[]  
  7.   
  8.    def build_block(self):  
  9.        print(f"Block built with Name {self.name} with size {self.size} unit")  
In the above code, we can see that we provided the implementation for BuildBlock method. Based on our need we can make concrete or non-concreate methods as well.
 
Below the client class code:
  1. from abstractBlock import AbstractBlock  
  2. from block import Block  
  3. import json  
  4.   
  5. smartCity=Block()  
  6. smartCity.name="smartCity"  
  7. smartCity.size=10000  
  8.   
  9. smartlayOut=Block()  
  10. smartlayOut.name="SmartlayOut"  
  11. smartlayOut.size=10000  
  12. smartCity.sub_blocks.append(smartlayOut)  
  13.   
  14. smartHome=Block()  
  15. smartHome.name="smartHome"  
  16. smartHome.size=1000  
  17. smartlayOut.sub_blocks.append(smartHome)  
  18.   
  19. smartRoom=Block()  
  20. smartRoom.name="smartRoom"  
  21. smartRoom.size=1000  
  22. smartHome.sub_blocks.append(smartRoom)  
  23.   
  24. smartLocker=Block()  
  25. smartLocker.name="smartLocker"  
  26. smartLocker.size=20  
  27. smartRoom.sub_blocks.append(smartLocker)  
  28.   
  29. smartFolder=Block()  
  30. smartFolder.name="smartFolder"  
  31. smartFolder.size=10  
  32. smartLocker.sub_blocks.append(smartFolder)  
  33.   
  34. smartFile=Block()  
  35. smartFile.name="smartFile"  
  36. smartFile.size=5  
  37. smartFolder.sub_blocks.append(smartFile)  
  38.   
  39. def build(block:AbstractBlock):  
  40.     block.build_block()  
  41.     for sub_block in block.sub_blocks:  
  42.         build(sub_block)  
  43.   
  44.   
  45. build(smartCity)  
  46. print()  
  47. print(json.dumps(smartCity, default=lambda o: o.__dict__, sort_keys=True, indent=2))  
In the above code, we can see that the client has a unitized composite object and built first.
  • Smart City followed by Smart Layout
  • Smart Layout followed by Smart Home
  • Smart Home followed by Smart Room
  • Smart Room followed by Smart Locker
  • Smart Locker followed by Smart Folder
  • Smart Folder followed by Smart File
After executing this code, we can see the same hierarchy in json format. For easy understating, I serialized the object into JSON. Below is the output snap:
 
 
When we have a requirement of implementing some nested objects with the same type, then we can go for this design pattern.
 
We can extend this composite object to any extent with N numbers of blocks inside blocks.
 

Summary

 
Above is a simple example of using a composite design pattern. You can download the uploaded source code and try adding more blocks. I hope it helps.