· Cập nhật lần cuối

Factory Method

typescriptdesign-pattern

Factory Method

Purpose of using the Factory Method:

Compared to Simple Factory:

Steps to create and use the Factory Method:

  1. Create an abstract class for the “Product”.
  2. Create classes for specific products.
  3. Create an abstract class for the “Factory”.
  4. Create corresponding factories for the “Products”.
  5. Use the objects created through the Factories instead of creating them directly with new “Product”.

Examples

Without Factory Methods

When not using the factory method pattern:

interface Shape {
  draw(): void;
}

class Circle implements Shape {
  draw(): void {
    console.log("Drawing a Circle");
  }
}

class Square implements Shape {
  draw(): void {
    console.log("Drawing a Square");
  }
}

// new object
class Triangle implements Shape {
  draw(): void {
    console.log("Drawing a Triangle");
  }
}

function main() {
  const shapes: Shape[] = [];

  //  These code will be change if we add new objects.
  shapes.push(new Circle());
  shapes.push(new Square());
  shapes.push(new Triangle());

  shapes.forEach((shape) => shape.draw());
}

main();

Factory Methods Examples

//  1. Create an abstract class for the "Product".
abstract class Transport {
  name: string;
  deliver: () => void;
}

// 2. Create classes for specific products.
class Truck implements Transport {
  name: string;
  constructor(truckName: string) {
    this.name = truckName;
  }

  public deliver() {
    console.log(`${this.name} - running...`);
  }
}

class Ship implements Transport {
  name: string;
  constructor(shipName: string) {
    this.name = shipName;
  }

  public deliver() {
    console.log(`${this.name} - running...`);
  }
}

//  3. Create an abstract class for the "Factory".
abstract class Logistic {
  createTransport: () => Transport;
}

// 4. Create corresponding factories for the "Products".
class RoadLogistics implements Logistic {
  public createTransport() {
    return new Truck("Van");
  }
}

class SeaLogistics implements Logistic {
  public createTransport() {
    return new Ship("Ship");
  }
}

// 5. Use the objects created through the Factories instead of creating them directly with new "Product".
const roadLogistics = new RoadLogistics();
const truck = roadLogistics.createTransport();
truck.deliver();

const seaLogistics = new SeaLogistics();
const ship = seaLogistics.createTransport();
ship.deliver();

Simple Factory

interface Shape {
  draw(): void;
}

// Define Simple Factory
class ShapeFactory {
  static createShape(type: string): Shape {
    switch (type) {
      case "circle":
        return new Circle();
      case "square":
        return new Square();
      case "triangle":
        return new Triangle();
      default:
        throw new Error("Unknown shape type");
    }
  }
}

function mainSimpleFactory() {
  const shapes: Shape[] = [];

  shapes.push(ShapeFactory.createShape("circle"));
  shapes.push(ShapeFactory.createShape("square"));
  shapes.push(ShapeFactory.createShape("triangle"));

  shapes.forEach((shape) => shape.draw());
}

mainSimpleFactory();

References