
Structural Design Pattern - Composite
Author - Abdul Rahman (Content Writer)
Design Pattern
13 Articles
Table of Contents
What we gonna do?
Ever tried to build a navigation menu that can have submenus, and those submenus can have their own submenus, and so on? Welcome to the world of tree structures! In this article, let's break down the Composite Design Pattern in C#—the secret sauce for treating individual objects and groups of objects with the same code, no matter how deep the hierarchy goes.
Why we gonna do?
The Composite Pattern is a structural design pattern that lets you compose objects into tree-like structures to represent part-whole hierarchies. Why does this matter? Because it allows you to treat a single item and a group of items uniformly—no more special-case code for leaves versus branches.
Think about file systems, organization charts, or even UI menus. Each can be made up of items that are either simple (a file, a menu item) or complex (a directory, a submenu). The Composite Pattern lets you work with both using the same interface, making your code cleaner, more flexible, and easier to extend.
Here's the thing: without this pattern, you'd end up writing a lot of type-checking and branching logic. With it, you get recursion and polymorphism working together to make your life easier.
How we gonna do?
Let's implement the Composite Pattern using a simple navigation menu as our example. We'll create a tree structure where each menu can contain menu items or other menus (submenus). The goal? Render the whole menu with a single recursive call.
Composite Pattern Structure (ASCII Diagram)
+-------------------+ +---------------------+
| IMenuComponent |<----------| MenuItem |
+-------------------+ +---------------------+
| +Render() | | +Render() |
+-------------------+ +---------------------+
^
|
|
+-------------------+
| Menu |
+-------------------+
| -children |
| +Add(child) |
| +Remove(child) |
| +Render() |
+-------------------+
Step 1: Define the Component Interface
First, define a common interface for both menu items and menus:
public interface IMenuComponent
{
void Render(int depth = 0);
}
Step 2: Implement the Leaf (MenuItem)
The MenuItem is a leaf node—it doesn't have children:
public class MenuItem : IMenuComponent
{
public string Title { get; }
public MenuItem(string title) => Title = title;
public void Render(int depth = 0)
{
Console.WriteLine(new string(' ', depth * 2) + "- " + Title);
}
}
Step 3: Implement the Composite (Menu)
The Menu can contain both MenuItem and other Menu objects:
public class Menu : IMenuComponent
{
public string Title { get; }
private readonly List<IMenuComponent> _children = new();
public Menu(string title) => Title = title;
public void Add(IMenuComponent component) => _children.Add(component);
public void Remove(IMenuComponent component) => _children.Remove(component);
public void Render(int depth = 0)
{
Console.WriteLine(new string(' ', depth * 2) + "+ " + Title);
foreach (var child in _children)
{
child.Render(depth + 1);
}
}
}
Step 4: Build and Render the Menu Tree
Now, let's put it all together and see the Composite Pattern in action:
var rootMenu = new Menu("Main Menu");
var fileMenu = new Menu("File");
fileMenu.Add(new MenuItem("New"));
fileMenu.Add(new MenuItem("Open"));
fileMenu.Add(new MenuItem("Exit"));
var editMenu = new Menu("Edit");
editMenu.Add(new MenuItem("Undo"));
editMenu.Add(new MenuItem("Redo"));
rootMenu.Add(fileMenu);
rootMenu.Add(editMenu);
rootMenu.Add(new MenuItem("Help"));
rootMenu.Render();
// Output:
// + Main Menu
// + File
// - New
// - Open
// - Exit
// + Edit
// - Undo
// - Redo
// - Help
Step 5: Interactive Demo
Try the demo below to see how the Composite Pattern lets you build and render a menu tree interactively:
Step 6: Why This Pattern Rocks
- Uniform treatment: You can treat a single menu item and a whole menu the same way.
- Easy to extend: Add new types of menu components without changing client code.
- Recursive operations: Operations like rendering or calculating totals are naturally recursive.
- Cleaner code: No more type-checking or special cases for leaves vs. composites.
Summary
The Composite Design Pattern is your go-to tool for working with tree-like structures in .NET. Whether you're building menus, file systems, or organization charts, this pattern lets you treat individual objects and groups of objects with the same code. That means less boilerplate, fewer bugs, and more flexibility as your app grows.
Next time you need to model a hierarchy, reach for the Composite Pattern—and let recursion do the heavy lifting!