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.
- from abc import abstractmethod
-
- class AbstractBlock:
- name:str
- size:any
- sub_blocks=[]
-
- @abstractmethod
- def build_block(self):
- pass
Now implement a Composite object, i.e. Block by implementing/inheriting component i.e. in our code AbstractBlock
- from abstractBlock import AbstractBlock
-
- class Block(AbstractBlock):
-
- def __init__(self):
- self.sub_blocks =[]
-
- def build_block(self):
- 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:
- from abstractBlock import AbstractBlock
- from block import Block
- import json
-
- smartCity=Block()
- smartCity.name="smartCity"
- smartCity.size=10000
-
- smartlayOut=Block()
- smartlayOut.name="SmartlayOut"
- smartlayOut.size=10000
- smartCity.sub_blocks.append(smartlayOut)
-
- smartHome=Block()
- smartHome.name="smartHome"
- smartHome.size=1000
- smartlayOut.sub_blocks.append(smartHome)
-
- smartRoom=Block()
- smartRoom.name="smartRoom"
- smartRoom.size=1000
- smartHome.sub_blocks.append(smartRoom)
-
- smartLocker=Block()
- smartLocker.name="smartLocker"
- smartLocker.size=20
- smartRoom.sub_blocks.append(smartLocker)
-
- smartFolder=Block()
- smartFolder.name="smartFolder"
- smartFolder.size=10
- smartLocker.sub_blocks.append(smartFolder)
-
- smartFile=Block()
- smartFile.name="smartFile"
- smartFile.size=5
- smartFolder.sub_blocks.append(smartFile)
-
- def build(block:AbstractBlock):
- block.build_block()
- for sub_block in block.sub_blocks:
- build(sub_block)
-
-
- build(smartCity)
- print()
- 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.