The Composite Design Pattern is a structural pattern that allows you to compose objects into tree-like structures to represent part-whole hierarchies. This pattern treats both individual objects and compositions of objects uniformly. It’s useful when you need to work with hierarchies of objects and want to treat single objects and compositions of objects in a consistent way.

Components of the Composite Design Pattern:

  1. Component: The abstract base class or interface that declares the common interface for both leaf and composite objects.
  2. Leaf: The concrete class that represents individual objects in the composition. It implements the component interface.
  3. Composite: The concrete class that represents compositions of leaf objects. It implements the component interface and contains child components.

Simple Example:

Let’s use a file system example where we have File and Directory components. A Directory can contain multiple File or Directory objects, and we want to be able to treat both File and Directory objects uniformly.

1. Component Interface:

// Component interface
interface FileSystemComponent {
    void showDetails();
}

2. Leaf:

// Leaf class
class File implements FileSystemComponent {
    private String name;

    public File(String name) {
        this.name = name;
    }

    @Override
    public void showDetails() {
        System.out.println("File: " + name);
    }
}

3. Composite:

import java.util.ArrayList;
import java.util.List;

// Composite class
class Directory implements FileSystemComponent {
    private String name;
    private List<FileSystemComponent> components = new ArrayList<>();

    public Directory(String name) {
        this.name = name;
    }

    public void addComponent(FileSystemComponent component) {
        components.add(component);
    }

    public void removeComponent(FileSystemComponent component) {
        components.remove(component);
    }

    @Override
    public void showDetails() {
        System.out.println("Directory: " + name);
        for (FileSystemComponent component : components) {
            component.showDetails();
        }
    }
}

4. Client Code:

public class CompositePatternDemo {
    public static void main(String[] args) {
        // Create files
        File file1 = new File("File1.txt");
        File file2 = new File("File2.txt");

        // Create directories
        Directory directory1 = new Directory("Directory1");
        Directory directory2 = new Directory("Directory2");

        // Add files to directories
        directory1.addComponent(file1);
        directory2.addComponent(file2);

        // Create a main directory and add subdirectories to it
        Directory mainDirectory = new Directory("MainDirectory");
        mainDirectory.addComponent(directory1);
        mainDirectory.addComponent(directory2);

        // Show details of all components
        mainDirectory.showDetails();
    }
}

Explanation:

  1. Component Interface: FileSystemComponent is the common interface for both File and Directory.
  2. Leaf: File is a concrete class that represents an individual file and implements FileSystemComponent.
  3. Composite: Directory is a concrete class that represents a directory, which can contain other FileSystemComponent objects (either File or other Directory objects).
  4. Client Code: Demonstrates how to use the Directory and File classes to create a hierarchical structure and display details of all components.

Benefits of the Composite Design Pattern:

  • Uniformity: Treats both individual objects and compositions of objects uniformly, simplifying client code.
  • Flexibility: Allows clients to work with complex tree structures without needing to know the specifics of individual objects or compositions.
  • Scalability: Makes it easy to add new leaf or composite types without modifying existing code.

Use Cases of the Composite Design Pattern:

  • File Systems: Where files and directories need to be treated uniformly.
  • Graphics Systems: Where shapes (like lines and circles) are composed into complex drawings.
  • Menus and UI Components: Where individual items and menus (containing other items or menus) need to be managed uniformly.

The Composite Pattern is particularly useful when dealing with tree structures and hierarchies where operations need to be applied uniformly across both individual and composite elements.