Skip to content

Latest commit

 

History

History
329 lines (290 loc) · 7.41 KB

File metadata and controls

329 lines (290 loc) · 7.41 KB

Builder

File Structure

📦 src/builder
 ┣ 📜 builder.ts
 ┣ 📜 README.md
📦 test/builder
 ┣ 📜 builder.test.ts

Test

npm run test:builder

Breakdown

Key Points

  • Flexibility – Allows objects to be built in various configurations without modifying the underlying code.
  • Separation of Concerns – Keeps object creation separate from its actual use, making the codebase cleaner and more maintainable.
  • Client Control – Gives the client precise control over how an object is constructed by interacting with a builder.
  • Structured Construction – Ensures that complex objects are built in an organized and predictable manner.

Benefits

  • Improves Readability & Maintainability – By separating object creation from its representation, the code becomes easier to manage.
  • Encapsulates Object Construction Logic – Prevents long, unreadable constructor calls by providing a more intuitive way to create objects.
  • Supports Multiple Configurations – A single builder can construct different variations of an object without code duplication.
  • Ensures Consistency – Helps prevent partially constructed or invalid objects by enforcing a step-by-step process.

Drawbacks

  • 🚫 Increased Complexity – More classes & interfaces make the code harder to maintain.
  • 🚫 Verbose Code – Requires multiple setters and a build() method.
  • 🚫 Performance Overhead – Extra method calls slow down object creation.
  • 🚫 Not Ideal for Simple Objects – Overkill when a constructor suffices.
  • 🚫 Code Duplication – Multiple builders may repeat logic.
  • 🚫 Harder Debugging – Errors from missing fields appear at runtime.
  • 🚫 Dependency on Builder – Client code tightly couples to the builder.
  • 🚫 Breaks Encapsulation – Builder accesses all internal fields.

Example

Class Architecture

classDiagram
    class iNotification {
        <<abstract>>
        +send(message: string): void
    }

    class EmailNotification {
        +send(message: string): void
    }

    class SMSNotification {
        +send(message: string): void
    }

    class NotificationBuilder {
        <<interface>>
        +setRecipient(recipient: string): this
        +setSubject(subject: string): this
        +setMessage(message: string): this
        +build(): iNotification
    }

    class EmailNotificationBuilder {
        -recipient: string
        -subject: string
        -message: string
        +setRecipient(recipient: string): this
        +setSubject(subject: string): this
        +setMessage(message: string): this
        +build(): iNotification
    }

    class SMSNotificationBuilder {
        -recipient: string
        -message: string
        +setRecipient(recipient: string): this
        +setSubject(subject: string): this // Throws Error
        +setMessage(message: string): this
        +build(): iNotification
    }

    iNotification <|-- EmailNotification
    iNotification <|-- SMSNotification
    NotificationBuilder <|.. EmailNotificationBuilder
    NotificationBuilder <|.. SMSNotificationBuilder

Loading

Code - Snippet

/**
 * Abstract class for notifications.
 *
 * @abstract
 * @class
 */
abstract class iNotification {
  /**
   * Sends a message.
   *
   * @abstract
   * @param {string} message
   * @returns {void}
   */
  abstract send(message: string): void;
}

/**
 * Concrete class for email notifications.
 *
 * @class
 * @extends {iNotification}
 */
class EmailNotification extends iNotification {
  /**
   * Sends an email notification.
   *
   * @param {string} message
   * @returns {void}
   */
  send(message: string): void {
    console.log(`Sending Email Notification: ${message}`);
  }
}

/**
 * Concrete class for SMS notifications.
 *
 * @class
 * @extends {iNotification}
 */
class SMSNotification extends iNotification {
  send(message: string): void {
    console.log(`Sending SMS Notification: ${message}`);
  }
}

/**
 * Interface for notification builders.
 *
 * @interface
 */
interface NotificationBuilder {
  /**
   * Sets the recipient.
   *
   * @param {string} recipient
   * @returns {this}
   */
  setRecipient(recipient: string): this;
  /**
   * Sets the subject.
   *
   * @param {string} subject
   * @returns {this}
   */
  setSubject(subject: string): this;
  /**
   * Sets the message.
   *
   * @param {string} message
   * @returns {this}
   */
  setMessage(message: string): this;
  /**
   * Builds a notification.
   *
   * @returns {iNotification}
   */
  build(): iNotification;
}

/**
 * Concrete builder for email notifications.
 *
 * @class
 * @implements {NotificationBuilder}
 */
class EmailNotificationBuilder implements NotificationBuilder {
  /**
   * The recipient.
   *
   * @type {string}
   */
  private recipient: string = "";
  /**
   * The subject.
   *
   * @type {string}
   */
  private subject: string = "";
  /**
   * The message.
   *
   * @type {string}
   */
  private message: string = "";

  /**
   * Sets the recipient.
   *
   * @param {string} recipient
   * @returns {this}
   */
  setRecipient(recipient: string): this {
    this.recipient = recipient;
    return this;
  }

  /**
   * Sets the subject.
   *
   * @param {string} subject
   * @returns {this}
   */
  setSubject(subject: string): this {
    this.subject = subject;
    return this;
  }

  /**
   * Sets the message.
   *
   * @param {string} message
   * @returns {this}
   */
  setMessage(message: string): this {
    this.message = message;
    return this;
  }

  /**
   * Builds a notification.
   *
   * @returns {iNotification}
   */
  build(): iNotification {
    const email = new EmailNotification();
    console.log(`Building Email Notification to ${this.recipient}`);
    return email;
  }
}

/**
 * Concrete builder for SMS notifications.
 *
 * @class
 * @implements {NotificationBuilder}
 */
class SMSNotificationBuilder implements NotificationBuilder {
  /**
   * The recipient.
   *
   * @type {string}
   */
  private recipient: string = "";
  /**
   * The message.
   *
   * @type {string}
   */
  private message: string = "";

  /**
   * Sets the recipient.
   *
   * @param {string} recipient
   * @returns {this}
   */

  setRecipient(recipient: string): this {
    this.recipient = recipient;
    return this;
  }

  /**
   * Sets the subject.
   *
   * @param {string} subject
   * @returns {this}
   */
  setSubject(subject: string): this {
    throw new Error("Method not implemented.");
  }

  /**
   * Sets the message.
   *
   * @param {string} message
   * @returns {this}
   */
  setMessage(message: string): this {
    this.message = message;
    return this;
  }

  /**
   * Builds a notification.
   *
   * @returns {iNotification}
   */
  build(): iNotification {
    const sms = new SMSNotification();
    console.log(`Building SMS Notification to ${this.recipient}`);
    return sms;
  }
}

(() => {
  const emailBuilder = new EmailNotificationBuilder();
  const email = emailBuilder.setRecipient("John Doe").setSubject("Hello").setMessage("Hello, world!").build();
  email.send("Hello, world!");

  const smsBuilder = new SMSNotificationBuilder();
  const sms = smsBuilder.setRecipient("John Doe").setMessage("Hello, world!").build();
  sms.send("Hello, world!");
})();