Course contentsShow
← Rust
Lesson 653 of 1,9105. Type System and TraitsFree lesson

The Composite Pattern for Tree Structures

Represent complex part-whole relationships through uniform trait interfaces.

In this lesson, you will learn how to treat individual objects and groups of objects uniformly by using a common trait interface to build recursive tree structures.

The Problem of Heterogeneity

Imagine building a file system. You have File objects (leaves) and Directory objects (containers that hold files and other directories). If you want to calculate the total size of a directory, you normally have to check if an item is a file or a folder. This leads to messy if-else blocks or complex match statements. The Composite Pattern solves this by enforcing a uniform interface for both types.

Defining the Component

In Rust, we define a trait that declares the common behavior—like get_size()—that both leaf nodes and composite nodes must support.

trait FileSystemNode {
    fn get_size(&self) -> u32;
}

struct File { size: u32 }
impl FileSystemNode for File {
    fn get_size(&self) -> u32 { self.size }
}

struct Directory {
    children: Vec<Box<dyn FileSystemNode>>,
}

impl FileSystemNode for Directory {
    fn get_size(&self) -> u32 {
        // Uniformly call get_size on all children, 
        // regardless of whether they are Files or Directories
        self.children.iter().map(|child| child.get_size()).sum()
    }
}

Why this works

By having the Directory struct store its children as a Vec<Box<dyn FileSystemNode>>, you create a recursive data structure. The Directory doesn't need to know if a child is a simple File or another complex Directory; it only cares that the object implements FileSystemNode.

This pattern allows you to compose complex trees of objects and perform operations on the entire structure by calling a single method on the root node. The tree essentially collapses the difference between a "part" and a "whole," allowing your business logic to treat a single leaf and an entire branch as the same type of entity.

Key Takeaway: The Composite Pattern uses trait interfaces to abstract away the distinction between individual components and groups, allowing you to process recursive hierarchies with uniform, simplified code.