# Composite Design Pattern

The **Composite Design Pattern** is a **structural pattern** that allows us to build complex tree structures where individual objects and groups of objects are treated **uniformly**.

### **Concept**

It provides a way to **compose objects into tree structures** to represent **part-whole hierarchies**. The key idea is that both individual objects (leaves) and groups of objects (composites) implement the same interface, allowing uniform treatment.

**A simpler explanation**

The **Composite Design Pattern** helps us to create **nested structures** where both **single items** and **groups of items** are treated the same way.

### **Key Idea:**

Imagine we have a **university form application**. Some parts of the form have **individual fields** (like "Name" or "Email"), while others have **sections** (like "Personal Details" or "Preferences") that group multiple fields together.

With the **Composite Pattern**, both **single fields** and **sections** follow the same rules, making it easy to manage them as a whole. You can add, remove, or process them **without worrying about whether they are a single field or a group**.

In a **University Form Filling App**, different form fields (like text fields, checkboxes, and dropdowns) can be combined into sections or composite groups, allowing for a flexible and extensible form structure. The **Composite Design Pattern** is useful for this use-case because we need to treat individual objects and compositions of objects uniformly.

### Implementation:

We will implement a **FormComponent** interface with two types of components:

1. **Leaf Components** – Individual form fields like TextField, CheckboxField, and DropdownField.
    
2. **Composite Component** – A FormSection that can contain multiple fields or even other sections.
    

**Step 1 : Define the Component Interface**

```typescript
export interface FormComponent {
  render(): void;
}
```

**Step 2: Create Leaf Components (Individual Form Fields)**

```typescript
// TextField.ts
import { FormComponent } from "./FormComponent";

export class TextField implements FormComponent {
  constructor(private label: string, private value: string = "") {}

  render(): void {
    console.log(`TextField: ${this.label} = ${this.value}`);
  }
}

// CheckboxField.ts
import { FormComponent } from "./FormComponent";

export class CheckboxField implements FormComponent {
  constructor(private label: string, private checked: boolean = false) {}

  render(): void {
    console.log(`CheckboxField: ${this.label} = ${this.checked}`);
  }
}

// DropdownField.ts
import { FormComponent } from "./FormComponent";

export class DropdownField implements FormComponent {
  constructor(private label: string, private options: string[], private selected?: string) {}

  render(): void {
    console.log(`DropdownField: ${this.label} = ${this.selected ?? "Not selected"}`);
  }
}
```

**Step 3: Create Composite Component (Form Section)**

```typescript
// FormSection.ts
import { FormComponent } from "./FormComponent";

export class FormSection implements FormComponent {
  private components: FormComponent[] = [];

  constructor(private title: string) {}

  addComponent(component: FormComponent): void {
    this.components.push(component);
  }

  render(): void {
    console.log(`== Section: ${this.title} ==`);
    this.components.forEach((component) => component.render());
  }
}
```

**Step 4: Implement the Form and Render It**

```typescript
import { TextField } from "./TextField";
import { CheckboxField } from "./CheckboxField";
import { DropdownField } from "./DropdownField";
import { FormSection } from "./FormSection";

function main() {

    // Create form fields
    const nameField = new TextField("Full Name");
    const emailField = new TextField("Email");
    const acceptTerms = new CheckboxField("Accept Terms", false);
    const departmentDropdown = new DropdownField("Department", ["CS", "Math", "Physics"], "CS");

    // Create sections
    const personalSection = new FormSection("Personal Details");
    personalSection.addComponent(nameField);
    personalSection.addComponent(emailField);

    const preferenceSection = new FormSection("Preferences");
    preferenceSection.addComponent(departmentDropdown);
    preferenceSection.addComponent(acceptTerms);

    // Main Form
    const mainForm = new FormSection("University Admission Form");
    mainForm.addComponent(personalSection);
    mainForm.addComponent(preferenceSection);

    // Render the form
    mainForm.render();

}

main();
```

### **Advantages of Using Composite Pattern**

1. **Scalability** – Easily add new form fields and sections.
    
2. **Uniform Treatment** – Individual fields and sections are treated the same way.
    
3. **Flexibility** – New form structures can be created dynamically.
    
4. **Reusability** – Reuse sections across different forms.
    

### **Significance of the Composite Pattern**

1. **Works with Hierarchical Data**
    
    * Useful when dealing with **nested structures** like UI components, forms, file systems, organization charts, etc.
        
2. **Uniformity in Object Handling**
    
    * Treats both individual elements and their compositions **identically**, simplifying code and improving maintainability.
        
3. **Flexibility and Scalability**
    
    * Easy to add new types of components without modifying existing structures (**Open-Closed Principle**).
        
4. **Promotes Reusability**
    
    * We can define smaller **reusable components** and compose them into larger structures dynamically.
        

### **Benefits of the Composite Pattern**

**1\. Simplifies Client Code**

* Clients can work with **individual elements and composite groups uniformly**, reducing complexity.
    
* Example: A form section can contain **both** fields and nested sections without the client worrying about their types.
    

**2\. Facilitates Recursive Structures**

* It supports **recursive tree-like structures**, where composites can contain other composites.
    
* Example: A **university form** can have nested **sections**, which can themselves contain sub-sections.
    

**3\. Enhances Maintainability**

* Since components share a common interface, adding new **form field types** (e.g., DatePickerField) requires **no changes to existing code**.
    

**4\. Adheres to SOLID Principles**

* **Open/Closed Principle (OCP)** → You can extend the system with new components **without modifying existing code**.
    
* **Single Responsibility Principle (SRP)** → Each component (e.g., TextField, CheckboxField) has its own responsibility.
    

**5\. Supports Dynamic Composition**

* We can **dynamically** construct complex structures at runtime.
    
* Example: A **multi-step form** builder where sections are added based on user choices.
    

### <mark>How does the Composite Pattern apply to our code?</mark>

* In the **University Form application**, we have both **individual fields** (like TextField, CheckboxField) and **sections** (FormSection) that group multiple fields.
    
* The entire form behaves like a **tree**, where sections can contain **both** fields and other sections.
    

```typescript
const personalSection = new FormSection("Personal Details");
personalSection.addComponent(nameField);
personalSection.addComponent(emailField);

//FormSection is a composite that groups multiple form fields together.

//We add individual fields (nameField, emailField) to the section without treating 
//them differently.

//The form is structured like a tree, with sections (whole) containing form fields (parts).

//A section can contain fields, and a form can contain multiple sections.

//The entire form is a nested structure, just like a tree.

const mainForm = new FormSection("University Admission Form");
mainForm.addComponent(personalSection);
mainForm.addComponent(preferenceSection);

//mainForm is the whole, and it contains parts (personalSection, preferenceSection).
//These sections themselves contain smaller parts (form fields).

//Every form component (TextField, CheckboxField, DropdownField, FormSection) 
//implements the same FormComponent interface.

//This ensures that both individual fields and composite sections can be 
//treated in the same way.

export interface FormComponent {
  render(): void;
}

//Every form field (leaf) and form section (composite) implements this interface.

//Because of this, we can call .render() on both form fields and form sections 
//without checking their type.
```

The GITHUB code link is [<mark>here</mark>](https://github.com/hegde10122/DesignPatterns/blob/master/composite/main.ts)
