# Builder — Design Patterns

Source: https://www.skillbyai.com/en/design-patterns/c-builder

> Assemble complex objects step by step.

## Readable construction

**Intent:** separate the construction of a complex object from its representation, so it can be built step by step and validated before use. Builders shine when an object has many optional parts, ordering rules or validation: HTTP requests, SQL queries, test data, email messages. A **fluent** builder returns `this` from each step so calls chain. **Use it when** a constructor would need many optional parameters (the "telescoping constructor" smell) or when construction needs validation. **Avoid it when** an options object is enough: in TypeScript and Python, named/optional parameters or an object literal with defaults often replace a builder entirely. Builders remain idiomatic in Java, where there are no named arguments.

## An email builder

Validates before producing an immutable message.

```typescript
interface Email {
  readonly to: string[];
  readonly subject: string;
  readonly html: string;
  readonly cc: string[];
  readonly attachments: { name: string; data: Uint8Array }[];
}

class EmailBuilder {
  private to: string[] = [];
  private cc: string[] = [];
  private subject = '';
  private html = '';
  private attachments: Email['attachments'] = [];

  addTo(address: string) { this.to.push(address); return this; }
  addCc(address: string) { this.cc.push(address); return this; }
  withSubject(s: string) { this.subject = s; return this; }
  withHtml(h: string) { this.html = h; return this; }
  attach(name: string, data: Uint8Array) { this.attachments.push({ name, data }); return this; }

  build(): Email {
    if (this.to.length === 0) throw new Error('At least one recipient is required');
    if (!this.subject) throw new Error('Subject is required');
    return Object.freeze({ to: [...this.to], cc: [...this.cc], subject: this.subject,
                           html: this.html, attachments: [...this.attachments] });
  }
}

const email = new EmailBuilder()
  .addTo('asha@example.com')
  .withSubject('Your invoice')
  .withHtml('<p>Thanks for your order.</p>')
  .attach('invoice.pdf', pdfBytes)
  .build();
```

## Builders are great for test data

A test-data builder with sensible defaults lets each test override only the fields it cares about, for example `aUser().withRole('admin').build()`, which keeps tests short and intention-revealing.

**Quiz:** In TypeScript, what often replaces a simple builder?

- [ ] A Visitor
- [ ] A Singleton
- [ ] An Observer
- [x] An options object with defaults

*Answer:* An options object with defaults. Object literals give named, optional parameters.
