📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.
▶️ Subscribe to My YouTube Channel (176K+ subscribers): Java Guides on YouTube
▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube
In real-world backend development, especially in Spring Boot applications, you’ll often work with tree-like structures — such as product categories, menu items, permissions, organizational hierarchies, etc.
If you’ve ever struggled to manage a structure where both individual elements and groups of elements should be treated the same way, then the Composite Pattern can help.
In this article, we’ll cover:
- What the Composite Pattern is (in plain words)
- Where it's used in backend systems
- A full real-world example in Spring Boot — building a product category tree
- Step-by-step code with explanations
- Best practices and when not to use it
Let’s dive in.
🧠 What is the Composite Pattern?
The Composite Pattern is a structural design pattern used to treat individual objects and groups of objects in the same way.
You build a structure where both “leaf” and “composite” objects implement the same interface.
In simpler terms:
- A category may have subcategories
- A menu item may have submenus
- A task may have subtasks
And you want to perform the same operation (like display, count, search) no matter whether it’s a single item or a group.
📦 Real-World Example: Product Category Tree in E-Commerce
Let’s say you’re building an e-commerce app. You have product categories like this:
Electronics
├── Phones
│ ├── Android
│ └── iPhone
├── Laptops
├── Accessories
Each category might:
- Have a name
- Have child categories
- Perform an operation (e.g., print itself, collect product IDs, etc.)
Let’s implement this using the Composite Pattern in Spring Boot.
✅ Step 1: Create the Common Interface
public interface CategoryComponent {
String getName();
void print();
}
This will be used for both single categories and categories with children.
✅ Step 2: Create the Leaf — Simple Category
public class CategoryLeaf implements CategoryComponent {
private final String name;
public CategoryLeaf(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void print() {
System.out.println("- " + name);
}
}
This is a leaf node — it doesn’t have children.
✅ Step 3: Create the Composite — Category with Subcategories
import java.util.ArrayList;
import java.util.List;
public class CategoryComposite implements CategoryComponent {
private final String name;
private final List<CategoryComponent> children = new ArrayList<>();
public CategoryComposite(String name) {
this.name = name;
}
public void add(CategoryComponent component) {
children.add(component);
}
@Override
public String getName() {
return name;
}
@Override
public void print() {
System.out.println("+ " + name);
for (CategoryComponent child : children) {
child.print();
}
}
}
This class contains other components — which could be leaves or other composites.
✅ Step 4: Create a Service to Build and Use the Tree
import org.springframework.stereotype.Service;
@Service
public class CategoryService {
public CategoryComponent buildCategoryTree() {
CategoryComposite electronics = new CategoryComposite("Electronics");
CategoryComposite phones = new CategoryComposite("Phones");
phones.add(new CategoryLeaf("Android"));
phones.add(new CategoryLeaf("iPhone"));
CategoryComposite laptops = new CategoryComposite("Laptops");
laptops.add(new CategoryLeaf("Gaming"));
laptops.add(new CategoryLeaf("Business"));
CategoryLeaf accessories = new CategoryLeaf("Accessories");
electronics.add(phones);
electronics.add(laptops);
electronics.add(accessories);
return electronics;
}
public void displayCategories(CategoryComponent root) {
root.print();
}
}
Here we build the full category tree and print it using the same method (print()
) on any component — leaf or composite.
✅ Step 5: Create a REST Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/categories")
public class CategoryController {
@Autowired
private CategoryService categoryService;
@GetMapping("/print")
public String printTree() {
CategoryComponent root = categoryService.buildCategoryTree();
categoryService.displayCategories(root);
return "Category tree printed to console.";
}
}
When you call /api/categories/print
, it prints:
+ Electronics
+ Phones
- Android
- iPhone
+ Laptops
- Gaming
- Business
- Accessories
Why This Pattern Fits Here
Need | How Composite Pattern Helps |
---|---|
Multiple nested levels | Handles tree structures cleanly |
Unified operations | Call print() on any component |
Flexible structure | Add more subcategories without rewriting logic |
Reusability | Use the same interface across services or APIs |
Extend with More Features
You can add more methods to CategoryComponent
, like:
List<String> getAllCategoryNames();
And implement it differently in CategoryLeaf
and CategoryComposite
.
This allows recursive operations across your category tree — searching, exporting, counting, etc.
Where Else Can You Use This Pattern?
Use Case | Example |
---|---|
Permissions | User → Roles → Permissions |
Menus | Menu → Submenu → Action |
Tasks | Task → Subtasks → Sub-subtasks |
File Systems | Directory → Files/Subdirectories |
Organization Charts | Department → Teams → Members |
✅ Best Practices
- Keep the interface small – only methods common to all components
- Use recursion with care – especially for very deep trees
- Avoid direct
instanceof
checks – rely on polymorphism - Use Spring services only when needed – keep composites simple and stateless if possible
- Build trees outside of the controller – separate concerns cleanly
⚠️ When Not to Use Composite Pattern
Avoid this pattern if:
- You don’t have nested or hierarchical data
- The structure is always flat
- You only deal with one type of object
In those cases, a simple list or map might be enough.
Summary
Step | What We Did |
---|---|
1 | Created a CategoryComponent interface |
2 | Implemented CategoryLeaf for basic categories |
3 | Implemented CategoryComposite for nested categories |
4 | Built a category tree in a Spring Boot service |
5 | Printed the tree via a controller endpoint |
The Composite Pattern lets you treat complex trees the same way you treat single nodes — keeping your logic simple and scalable.
Final Thoughts
Tree-like data structures are everywhere in backend applications. The Composite Pattern gives you a clean, reusable way to model them — especially in Java and Spring Boot projects.
By applying this pattern:
- You simplify your logic
- Avoid repetitive code
- Make it easy to extend the structure in the future
If you find yourself writing recursive logic with a mix of “item” and “group of items” — it's probably time to use the Composite Pattern.
Comments
Post a Comment
Leave Comment