Dustin Boston

Builder Pattern

The Builder pattern decouples construction of an object from its underlying structure so that one builder can create multiple types of objects.

Source Code Listing

code.ts

class Part<T> {
  constructor(
    public type: string,
    public value: T,
  ) {}
}

class Director<T> {
  constructor(public builder: Builder<T>) {}

  construct(structure: Array<Part<T>>) {
    for (const part of structure) {
      switch (part.type) {
        case "a": {
          this.builder.buildPartA(part);
          break;
        }

        case "b": {
          this.builder.buildPartB(part);
          break;
        }

        default: {
          this.builder.buildPartA(part);
        }
      }
    }
  }
}

class Product<U> {
  constructor(public result: U[] = []) {}

  append(object: U) {
    this.result.push(object);
  }

  get() {
    return this.result;
  }
}

class Builder<T> {
  buildPartA(_part: Part<T>) {
    // Unimplemented
  }

  buildPartB(_part: Part<T>) {
    // Unimplemented
  }
}

class ConcreteBuilder1<T, U> extends Builder<T> {
  product = new Product<U>();

  buildPartA(part: Part<T>) {
    // Example building a part
    const value: U = String(part.value).toLowerCase() as unknown as U;
    this.product.append(value);
  }

  buildPartB(part: Part<T>) {
    // Example building a part
    const value: U = String(part.value).toUpperCase() as unknown as U;
    this.product.append(value);
  }

  getResult() {
    return this.product;
  }
}

// Other builders:
// class ConcreteBuilder2<T, U> extends Builder<T> {
// class ConcreteBuilder3<T, U> extends Builder<T> {

const client = {
  run() {
    const concreteBuilder = new ConcreteBuilder1<string, string>();
    const director = new Director(concreteBuilder);
    director.construct([new Part("a", "Hello"), new Part("b", "World")]);
    const result = concreteBuilder.getResult();
    console.log(result.get());
  },
};

client.run();

Tags

[End]