[Typescript] Builder pattern - 01

The builder pattern is a design pattern commonly used in OOP.

It is used to create complex objects step by step throught a series of methods, each of which addes some details to the final object.

The goal of the builder pattern is to separate the construction of an obhect from its representation, so that the same construction process can create different represetntations.

 

The builder pattern is often used to create object that have a large number of optional fields or when it's ncessary to build objects iwth many combinations of data.

It provides a way to create objects in a clean, efficient, and flexible way, without having to make the user of the object aware of the implementataion details.

 

class Sandwich {
    private bread: string;
    private meat: string;
    private cheese: string;
    private toppings: string[];

    constructor(builder: SandwichBuilder) {
        this.bread = builder.bread;
        this.meat = builder.meat;
        this.cheese = builder.cheese;
        this.toppings = builder.toppings;
    }

    public static get Builder() {
        return SandwichBuilder;
    }
}

class SandwichBuilder {
    public bread: string;
    public meat: string;
    public cheese: string;
    public toppings: string[];

    constructor() {
        this.bread = 'White';
        this.meat = 'Turkey';
        this.cheese = 'Cheddar';
        this.toppings = ['Lettuce'];
    }

    public withBread(bread: string): SandwichBuilder {
        this.bread = bread;
        return this;
    }

    public withMeat(meat: string): SandwichBuilder {
        this.meat = meat;
        return this;
    }

    public withCheese(cheese: string): SandwichBuilder {
        this.cheese = cheese;
        return this;
    }

    public withToppings(toppings: string[]): SandwichBuilder {
        this.toppings = toppings;
        return this;
    }

    public build(): Sandwich {
        return new Sandwich(this);
    }
}

const sandwich = new Sandwich.Builder()
    .withBread('Wheat')
    .withMeat('Roast Beef')
    .withCheese('Swiss')
    .withToppings(['Tomatoes', 'Onions'])
    .build();

 

Typescript with typesafe version:

查看代码
 type Topping = "Tomatoes" | "Onions" | "Lettuce";

export class Sandwich<
  Bread extends "White" | "Wheat",
  Meat extends "Roast Beef" | "Turkey",
  Cheese extends "Swiss" | "Cheddar",
  Toppings extends Topping[]
> {
  private bread: Bread;
  private meat: Meat;
  private cheese: Cheese;
  private toppings: Toppings;

  constructor(builder: SandwichBuilder<Bread, Meat, Cheese, Toppings>) {
    this.bread = builder.bread;
    this.meat = builder.meat;
    this.cheese = builder.cheese;
    this.toppings = builder.toppings;
  }

  public static get Builder() {
    return SandwichBuilder;
  }
}

class SandwichBuilder<
  Bread extends "White" | "Wheat",
  Meat extends "Roast Beef" | "Turkey",
  Cheese extends "Swiss" | "Cheddar",
  Toppings extends Topping[]
> {
  public bread: Bread;
  public meat: Meat;
  public cheese: Cheese;
  public toppings: Toppings;

  constructor() {
    this.bread = "White" as Bread;
    this.meat = "Turkey" as Meat;
    this.cheese = "Cheddar" as Cheese;
    this.toppings = ["Lettuce"] as Toppings;
  }

  public withBread(): SandwichBuilder<"White", Meat, Cheese, Toppings>;
  public withBread<T extends Bread>(
    bread: T
  ): SandwichBuilder<T, Meat, Cheese, Toppings>;
  public withBread(bread: Bread = this.bread) {
    this.bread = bread;
    return this as any;
  }

  withMeat(): SandwichBuilder<Bread, "Turkey", Cheese, Toppings>;
  withMeat<T extends Meat>(
    meat: T
  ): SandwichBuilder<Bread, T, Cheese, Toppings>;
  public withMeat(meat: Meat = this.meat) {
    this.meat = meat;
    return this as any;
  }

  public withCheese(): SandwichBuilder<Bread, Meat, "Cheddar", Toppings>;
  public withCheese<T extends Cheese>(
    cheese: T
  ): SandwichBuilder<Bread, Meat, T, Toppings>;
  public withCheese(cheese: Cheese = this.cheese) {
    this.cheese = cheese;
    return this as any;
  }

  public withToppings(): SandwichBuilder<Bread, Meat, Cheese, ["Lettuce"]>;
  public withToppings<T extends Toppings>(
    toppings: T
  ): SandwichBuilder<Bread, Meat, Cheese, T>;
  public withToppings(toppings: Toppings = this.toppings) {
    this.toppings = toppings;
    return this as any;
  }

  public build(): Sandwich<Bread, Meat, Cheese, Toppings> {
    return new Sandwich(this);
  }
}

const sandwich = new Sandwich.Builder()
  .withBread("Wheat")
  .withMeat("Roast Beef")
  .withCheese("Swiss")
  .withToppings(["Tomatoes", "Onions"])
  .build();
posted @ 2023-02-13 16:41  Zhentiw  阅读(21)  评论(0编辑  收藏  举报