Website logo
Menu

Factory Method pattern in TypeScript

Author's avatar
José Miguel Álvarez VañóNovember 7, 2022

Introduction

The factory method pattern is a creational pattern which provides an interface to create objects in a parent class. Subclasses of that class can override the method that creates the objects to change the type of object that will be created.

This way the creation of the objects is decoupled from the rest of the code.

Applicability

Use the factory method pattern when:

Implementation

You can find the full example source code here.

Diagram of the factory method pattern. Credit: Vanderjoe - Wikimedia Commons
  1. Define an abstract interface for the object that will be created.

In the example I'm going to handle payments so I'm going to use the following interface:

interface Payment {
  creditCard: number;
}
  1. Define an abstract class which will have an abstract method to create the objects. In this class you can include any common logic that the objects created by the subclasses will need.

In this example, createPayment is the abstract method that will be implemented by the subclasses. It could also be possible to have a default implementation of this method in the abstract class if you want to have some default setup.

Apart from this, I'm including the method completePayment which will be common to all the objects created by the subclasses.

abstract class PaymentGateway {
  public abstract createPayment(creditCard: number, ...args: any[]): Payment;

  public completePayment(payment: Payment): void {
    console.log(
      `Payment with credit card ${payment.creditCard} successfully completed using the PaymentGateway`
    );
  }
}
  1. Define concreted implementations of the object interface that was defined in the first step.

In the example I will have PhysicalPayment and OnlinePayment.

interface PhysicalPayment extends Payment {
  storeLocation: string;
}

interface OnlinePayment extends Payment {
  email: string;
}
  1. Finally, define the subclasses of the abstract class that will implement the createPayment method.

As I have two different object types, I will create two new classes: PhysicalPaymentGateway and OnlinePaymentGateway.

class PhysicalPaymentGateway extends PaymentGateway {
  public createPayment(
    creditCard: number,
    storeLocation: string
  ): PhysicalPayment {
    return {
      creditCard,
      storeLocation,
    };
  }
}

class OnlinePaymentGateway extends PaymentGateway {
  public createPayment(creditCard: number, email: string): OnlinePayment {
    return {
      creditCard,
      email,
    };
  }
}
  1. The factory method is now ready to be used.

An example of how client code would create objects for the online variant:

const onlinePaymentGateway = new OnlinePaymentGateway();
const onlinePayment = onlinePaymentGateway.createPayment(
  987654321,
  "test@example.com"
);
onlinePaymentGateway.completePayment(onlinePayment);

An this is how the client would use the physical variant:

const physicalPaymentGateway = new PhysicalPaymentGateway();
const physicalPayment = physicalPaymentGateway.createPayment(
  123456789,
  "New York"
);
physicalPaymentGateway.completePayment(physicalPayment);

Advantages

As always, make sure it makes sense to use this pattern in your application. Otherwise you could be introducing unnecessary complexity.

Resources

GitHub profileTwitter profileLinkedIn profile
José Miguel Álvarez Vañó
© 2022
jmalvarez.dev