Javascript design patterns: Factory Method

The Factory Method pattern belongs to the group of creational design patterns. Its main purpose is to create configurable objects based on given data.

đź“• Vocabulary: In object-oriented programming a factory is a regular function that returns a new instance of an object and doesn’t need the new keyword.

Javascript implementation

in concrete, it is useful when you need to create an object with different configurations. For example, let’s think about instantiating a widget with different data for different environments.

// Factory function
const createWidget = ({ apiKey, secretKey, environment = 'production' }) => ({
  apiKey,
  secretKey,
  environment,
  run() {
    return `start ${this.environment} with key ${this.apiKey}`;
  }
});

const productionWidget = createWidget({
  apiKey: 'productionApiKey',
  secretKey: 'productionSecretKey',
});

const stagingWidget = createWidget({
  apiKey: 'developApiKey',
  secretKey: 'developSecretKey',
  environment: 'staging'
});

productionWidget.run()
stagingWidget.run()

Typescript implementation

In typescript, we can also have an additional level of abstraction using an abstract function

// Widget Interface
interface Widget {
  apiKey: string;
  secretKey: string;
  environment: 'production' | 'staging';
  run(): string;
}

// Abstract factory function
function createAbstractWidget(config: {
  apiKey: string;
  secretKey: string;
  environment?: 'production' | 'staging';
}): Widget {
  if (!config.apiKey || !config.secretKey) {
    throw new Error('Missing required parameters: apiKey and secretKey');
  }
  return {
    apiKey: config.apiKey,
    secretKey: config.secretKey,
    environment: config.environment || 'production',
    run() {
      return `start ${this.environment} with key ${this.apiKey}`;
    },
  };
}

// Concrete factory functions
function createProductionWidget(): Widget {
  return createAbstractWidget({
    apiKey: 'productionApiKey',
    secretKey: 'productionSecretKey',
  });
}
function createStagingWidget(): Widget {
  return createAbstractWidget({
    apiKey: 'developApiKey',
    secretKey: 'developSecretKey',
    environment: 'staging',
  });
}

const productionWidget = createProductionWidget();
const stagingWidget = createStagingWidget();
productionWidget.run()
stagingWidget.run()

Wrapping up

In the most classical implementation, the pattern factory method makes use of three entities:

  • The factory: Responsible for creating a new object
  • Abstract function: (Only TypeScript) The interface of the object
  • Concrete function: Creates the effective object

Disavantages

For me, the most well-founded criticism of this pattern in javascript is that it violates the open–closed principle (OCP), which is that in software engineering a system should be open for extension but closed for change.

References

Irene Iaccio

Freelance web developer

Subscribe to the monthly digest!

I'll use your email only to send you the latest posts once a month.