Factory Pattern

Med

The Factory Pattern delegates object creation to a dedicated function or method, decoupling the calling code from concrete constructors. It is one of the most commonly used patterns in JavaScript for creating objects that share an interface but differ in implementation.

Interactive Visualization

Creational Patterns

IIFE creates private scope, returns public API via closure
returnscloses overcallsIIFE Scopeprivate varsPublic APIConsumer
1 / 3

Understanding Factory Pattern

The Factory Pattern is one of the most practical design patterns in JavaScript. At its core, it replaces direct object construction (new ClassName()) with a function call that returns the correct object based on parameters. This seemingly simple change has profound consequences: callers no longer need to know which class to instantiate, new types can be added without modifying consumer code, and complex construction logic is centralized.

In JavaScript, factory functions are especially idiomatic because they avoid the confusion of prototypes and the new keyword. A factory function is just a regular function that returns an object. There is no prototype chain, no this binding ambiguity, and no need for instanceof checks. This simplicity is why many JavaScript experts prefer factory functions over classes for object creation.

The pattern scales from simple switch-based factories to extensible registry-based systems. A registry-based factory allows plugins to register new types at runtime, making it ideal for plugin architectures, transport layers, and UI component systems. Abstract factories take this further by creating families of related objects, ensuring that all objects in a set are compatible with each other.

Key Points

  • A factory function returns new objects without using the new keyword or exposing constructors
  • Decouples object creation from usage — callers depend on an interface, not a class
  • The Simple Factory centralizes creation logic in a single function with a type parameter
  • The Factory Method pattern lets subclasses override the creation method to produce different objects
  • The Abstract Factory creates families of related objects without specifying concrete classes
  • JavaScript favors factory functions over classes because they avoid prototype complexity

Code Examples

Simple Factory Function

function createUser(type, name) {
  const base = { name, createdAt: Date.now() };

  switch (type) {
    case 'admin':
      return { ...base, role: 'admin', permissions: ['read', 'write', 'delete'] };
    case 'editor':
      return { ...base, role: 'editor', permissions: ['read', 'write'] };
    case 'viewer':
      return { ...base, role: 'viewer', permissions: ['read'] };
    default:
      throw new Error('Unknown user type: ' + type);
  }
}

const admin = createUser('admin', 'Alice');
const viewer = createUser('viewer', 'Bob');

One function, multiple object shapes. Callers never need to know the internal structure.

Factory with Registration

const transportFactory = (() => {
  const registry = new Map();

  return {
    register(type, creator) {
      registry.set(type, creator);
    },
    create(type, config) {
      const creator = registry.get(type);
      if (!creator) throw new Error('Unknown: ' + type);
      return creator(config);
    },
  };
})();

transportFactory.register('http', (cfg) => ({
  send(data) { console.log('HTTP POST', cfg.url, data); },
}));

transportFactory.register('websocket', (cfg) => ({
  send(data) { console.log('WS send', cfg.url, data); },
}));

const t = transportFactory.create('http', { url: '/api' });
t.send({ msg: 'hello' });

A registry lets third-party code add new types without modifying the factory.

Abstract Factory

function createUIKit(theme) {
  if (theme === 'dark') {
    return {
      createButton: (label) => ({ label, bg: '#333', color: '#fff' }),
      createInput: (placeholder) => ({ placeholder, bg: '#222', border: '#555' }),
    };
  }
  return {
    createButton: (label) => ({ label, bg: '#fff', color: '#333' }),
    createInput: (placeholder) => ({ placeholder, bg: '#fafafa', border: '#ccc' }),
  };
}

const kit = createUIKit('dark');
const btn = kit.createButton('Submit');
const input = kit.createInput('Email...');

The abstract factory returns a family of related creators, ensuring consistent theming across all components.

Common Mistakes

  • Overcomplicating simple object creation — use a plain object literal when no polymorphism is needed
  • Returning inconsistent shapes from different factory branches, breaking the shared interface contract
  • Not validating the type parameter, leading to silent undefined returns
  • Confusing factory functions with constructor functions — factories do not use new
  • Growing the switch statement endlessly instead of using a registry for extensibility

Interview Tips

  • Emphasize that factories decouple creation from usage — the caller depends on an interface, not a class
  • Know the three levels: Simple Factory, Factory Method, Abstract Factory
  • Mention real-world uses: React.createElement, document.createElement, Express middleware factories
  • Explain when NOT to use it — YAGNI applies if you only ever create one type

Related Concepts