Introduction
A composite design pattern is a structural design pattern. It allows developers to create multiple nested objects of the same type to complete one single system hierarchy.
Players in this pattern
- Component: This player defines base contract with composite class to allow the creation of nested objects.
- Composite: This the player that will implement the contract defined by the component.
- Client: With the help of a composite player, this player 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 players.
- AbstractBlock Component
- Block Composite
- Client
We will build an Abstract block with Add and remove block features. If we want we can implement Add and Remove features explicitly. In my case I am using List, by default I will have Add, and Remove features available for adding/removing blocks.
using System.Collections.Generic;
namespace Composite.Design.Pattern.Demo.Contract
{
public abstract class AbstractBlock
{
public string Name { get; set; }
public double Size { get; set; }
public abstract void BuildBlock();
public List<AbstractBlock> SubBlocks { get; set; }
}
}
Now implement Composite object; i.e., Block by implementing/inheriting component i.e. in our code AbstractBlock.
using Composite.Design.Pattern.Demo.Contract;
using System.Collections.Generic;
using static System.Console;
namespace Composite.Design.Pattern.Demo.Business
{
public class Block : AbstractBlock
{
public Block()
{
SubBlocks = new List<AbstractBlock>();
}
public override void BuildBlock() => WriteLine($"Block built with Name {Name} with size {Size} unit");
}
}
In the above code we can see that, we provided the implementation for the BuildBlock method. Based on our needs we can make concrete or non-concreate methods as well.
Below is the client class code.
using Composite.Design.Pattern.Demo.Contract;
using static System.Console;
using Composite.Design.Pattern.Demo.Business;
using Newtonsoft.Json;
namespace Composite.Design.Pattern.Demo
{
class Client
{
static void Main(string[] args)
{
AbstractBlock smartCity = new Block
{
Name = "SmartCity",
Size = 100000
};
AbstractBlock smartlayOut = new Block()
{
Name = "SmartlayOut",
Size = 10000,
};
smartCity.SubBlocks.Add(smartlayOut);
AbstractBlock smartHome = new Block()
{
Name = "smartHome",
Size = 1000,
};
smartlayOut.SubBlocks.Add(smartHome);
AbstractBlock smartRoom = new Block()
{
Name = "smartRoom",
Size = 1000,
};
smartHome.SubBlocks.Add(smartRoom);
AbstractBlock smartLocker = new Block()
{
Name = "smartLocker",
Size = 20,
};
smartRoom.SubBlocks.Add(smartLocker);
AbstractBlock smartFolder = new Block()
{
Name = "smartFolder",
Size = 10,
};
smartRoom.SubBlocks.Add(smartFolder);
AbstractBlock smartFile = new Block()
{
Name = "smartFile",
Size = 5,
};
smartFolder.SubBlocks.Add(smartFile);
Build(smartCity);
WriteLine();
string json = JsonConvert.SerializeObject(smartCity, Formatting.Indented);
WriteLine(json);
ReadLine();
}
private static void Build(AbstractBlock block)
{
block.BuildBlock();
block?.SubBlocks?.ForEach(b => Build(b));
}
}
}
In the above code, we can see that the client has utilized a composite object and built the 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.
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 number 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.