# Composite Pattern

> Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions uniformly.

## Problem

You have a file system with files and directories. A directory can contain files and other directories. You need to calculate the total size of any node — whether it's a single file or an entire directory tree — using the same interface.

## Solution

Define a common `Component` interface with a `size()` method. `File` is a leaf that returns its own size. `Directory` is a composite that sums the sizes of its children.

```
        ┌──────────────────┐
        │ Component (intf) │
        │ + size(): int    │
        │ + name(): string │
        └──────┬───────────┘
               │
       ┌───────┴───────┐
       │               │
  ┌────┴────┐   ┌──────┴──────┐
  │  File   │   │  Directory  │
  │ (leaf)  │   │ (composite) │
  └─────────┘   │ + children  │
                │ + add()     │
                └─────────────┘
```

## When to Use

- You need to represent part-whole hierarchies (trees).
- You want clients to treat individual objects and compositions uniformly.
- You want to add new leaf or composite types without changing client code.

## When to Avoid

- The structure is flat with no nesting — a simple list suffices.
- Leaf and composite operations differ significantly, making a uniform interface forced.
- You need strict type safety between leaf and composite at compile time.

## Pseudocode

```
interface Component:
    method size(): int
    method name(): string

class File implements Component:
    field _name: string
    field _size: int

    constructor(name, size):
        this._name = name
        this._size = size

    method size(): return _size
    method name(): return _name

class Directory implements Component:
    field _name: string
    field children: list<Component>

    constructor(name):
        this._name = name
        this.children = []

    method add(child: Component):
        children.append(child)

    method size():
        total = 0
        for child in children:
            total += child.size()
        return total

    method name(): return _name

// Usage
root = Directory("root")
root.add(File("readme.md", 100))
src = Directory("src")
src.add(File("main.py", 500))
src.add(File("utils.py", 300))
root.add(src)
print root.name() + " total size: " + root.size()
```

## Python

```python
from abc import ABC, abstractmethod


class Component(ABC):
    """Common interface for files and directories."""

    @abstractmethod
    def size(self) -> int: ...

    @abstractmethod
    def name(self) -> str: ...

    def display(self, indent: int = 0) -> None:
        print(f"{'  ' * indent}{self.name()} ({self.size()} bytes)")


class File(Component):
    """Leaf node."""

    def __init__(self, name: str, size: int) -> None:
        self._name = name
        self._size = size

    def size(self) -> int:
        return self._size

    def name(self) -> str:
        return self._name


class Directory(Component):
    """Composite node that contains children."""

    def __init__(self, name: str) -> None:
        self._name = name
        self._children: list[Component] = []

    def add(self, child: Component) -> "Directory":
        self._children.append(child)
        return self

    def size(self) -> int:
        return sum(child.size() for child in self._children)

    def name(self) -> str:
        return self._name

    def display(self, indent: int = 0) -> None:
        print(f"{'  ' * indent}{self.name()}/ ({self.size()} bytes)")
        for child in self._children:
            child.display(indent + 1)


if __name__ == "__main__":
    root = Directory("root")
    root.add(File("readme.md", 100))
    root.add(File(".gitignore", 50))

    src = Directory("src")
    src.add(File("main.py", 500))
    src.add(File("utils.py", 300))

    tests = Directory("tests")
    tests.add(File("test_main.py", 400))

    src.add(tests)
    root.add(src)

    root.display()
    print(f"\nTotal size: {root.size()} bytes")
```

**Output:**
```
root/ (1350 bytes)
  readme.md (100 bytes)
  .gitignore (50 bytes)
  src/ (1200 bytes)
    main.py (500 bytes)
    utils.py (300 bytes)
    tests/ (400 bytes)
      test_main.py (400 bytes)

Total size: 1350 bytes
```

## Go

```go
package main

import (
	"fmt"
	"strings"
)

// Component is the common interface.
type Component interface {
	Size() int
	Name() string
	Display(indent int)
}

// File is a leaf node.
type File struct {
	name string
	size int
}

func NewFile(name string, size int) *File {
	return &File{name: name, size: size}
}

func (f *File) Size() int    { return f.size }
func (f *File) Name() string { return f.name }
func (f *File) Display(indent int) {
	fmt.Printf("%s%s (%d bytes)\n", strings.Repeat("  ", indent), f.name, f.size)
}

// Directory is a composite node.
type Directory struct {
	name     string
	children []Component
}

func NewDirectory(name string) *Directory {
	return &Directory{name: name}
}

func (d *Directory) Add(c Component) *Directory {
	d.children = append(d.children, c)
	return d
}

func (d *Directory) Size() int {
	total := 0
	for _, child := range d.children {
		total += child.Size()
	}
	return total
}

func (d *Directory) Name() string { return d.name }

func (d *Directory) Display(indent int) {
	fmt.Printf("%s%s/ (%d bytes)\n", strings.Repeat("  ", indent), d.name, d.Size())
	for _, child := range d.children {
		child.Display(indent + 1)
	}
}

func main() {
	root := NewDirectory("root")
	root.Add(NewFile("readme.md", 100))
	root.Add(NewFile(".gitignore", 50))

	src := NewDirectory("src")
	src.Add(NewFile("main.py", 500))
	src.Add(NewFile("utils.py", 300))

	tests := NewDirectory("tests")
	tests.Add(NewFile("test_main.py", 400))
	src.Add(tests)

	root.Add(src)

	root.Display(0)
	fmt.Printf("\nTotal size: %d bytes\n", root.Size())
}
```

**Output:**
```
root/ (1350 bytes)
  readme.md (100 bytes)
  .gitignore (50 bytes)
  src/ (1200 bytes)
    main.py (500 bytes)
    utils.py (300 bytes)
    tests/ (400 bytes)
      test_main.py (400 bytes)

Total size: 1350 bytes
```

## JavaScript

```javascript
class File {
  constructor(name, size) {
    this._name = name;
    this._size = size;
  }

  size() {
    return this._size;
  }
  name() {
    return this._name;
  }

  display(indent = 0) {
    console.log(`${"  ".repeat(indent)}${this.name()} (${this.size()} bytes)`);
  }
}

class Directory {
  constructor(name) {
    this._name = name;
    this._children = [];
  }

  add(child) {
    this._children.push(child);
    return this;
  }

  size() {
    return this._children.reduce((sum, child) => sum + child.size(), 0);
  }

  name() {
    return this._name;
  }

  display(indent = 0) {
    console.log(
      `${"  ".repeat(indent)}${this.name()}/ (${this.size()} bytes)`
    );
    for (const child of this._children) {
      child.display(indent + 1);
    }
  }
}

// --- Main ---
const root = new Directory("root");
root.add(new File("readme.md", 100));
root.add(new File(".gitignore", 50));

const src = new Directory("src");
src.add(new File("main.py", 500));
src.add(new File("utils.py", 300));

const tests = new Directory("tests");
tests.add(new File("test_main.py", 400));
src.add(tests);

root.add(src);

root.display();
console.log(`\nTotal size: ${root.size()} bytes`);
```

**Output:**
```
root/ (1350 bytes)
  readme.md (100 bytes)
  .gitignore (50 bytes)
  src/ (1200 bytes)
    main.py (500 bytes)
    utils.py (300 bytes)
    tests/ (400 bytes)
      test_main.py (400 bytes)

Total size: 1350 bytes
```

## Related Patterns

- **Iterator** — use iterator to traverse composite trees without exposing the tree structure to the client.
- **Visitor** — visitor lets you add operations to composite trees without modifying node classes.
- **Decorator** — decorator adds responsibilities to a single object; composite organises objects into tree structures.
- **Flyweight** — use flyweight to share leaf node data when the composite tree contains many identical leaves.
