Skip to Content
Course content

159: The Factory Pattern

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was helping a teammate with a game project. He had a "Combat Manager" file that was nearly 800 lines long, and about half of that was just a massive switch statement used to spawn enemies. Every time he wanted to create an Orc, a Goblin, or a Skeleton, he had to manually instantiate the class, pass in the specific health values, set the attack speed, and assign a loot table. When the lead designer decided that every enemy needed a new "Elemental" property, my teammate spent an entire afternoon hunting down every single new Enemy() call across the codebase to update the constructor arguments. It was a tedious, error-prone slog that could have been avoided entirely.

Abstracting the Creation Logic

This is where the Factory Pattern comes in. At its core, a factory is just a function (or a class with a static method) that handles the complexity of creating objects. Instead of you calling new User() or new Admin() all over your app, you call a factory and tell it what you need. The factory decides which class to instantiate and how to configure it before handing it back to you.

Think of it as a middleman. You don't care how the object is built; you just care that it follows the interface you expect. In JavaScript, this is particularly powerful because we aren't strictly bound by types, but the architectural benefit remains: you decouple the consumption of an object from its creation.

const Orc = {
  type: 'Orc',
  attack: () => console.log('Swings a heavy axe!')
};

const Goblin = {
  type: 'Goblin',
  attack: () => console.log('Stabs with a rusty dagger!')
};

class MonsterFactory {
  static createMonster(type) {
    switch (type) {
      case 'orc':
        return { ...Orc, health: 100 };
      case 'goblin':
        return { ...Goblin, health: 50 };
      default:
        throw new Error('Monster type not recognized');
    }
  }
}

// Now the rest of the app doesn't need to know about Orc or Goblin specifics
const enemy1 = MonsterFactory.createMonster('orc');
const enemy2 = MonsterFactory.createMonster('goblin');

Decoupling for Future-Proofing

You might be thinking, "Why not just use a simple function?" To be fair, in JavaScript, a factory often is just a function. But the pattern's real value emerges as your project grows. When you use a factory, the "knowledge" of how to build a specific object lives in exactly one place. If you need to change the default health of all Goblins or add a new isElite flag to every spawned monster, you change it in the factory, and every other part of your system automatically receives the update.

I've found this is especially useful when dealing with API responses. If your backend sends a string like "premium_user", your factory can translate that string into a PremiumUser object with all the associated methods and permissions, keeping your UI components clean. You aren't littering your components with if (user.type === 'premium') logic; you're just interacting with an object that the factory guaranteed was built correctly.




📋 Practical Task

The Galactic Shipyard Constructor

You are building a space simulation. Instead of manually creating ships, you need to implement a Shipyard factory that handles the production of different vessel classes. Each ship must have a name, a firepower value, and a shieldStrength value.

Requirements:

  • Create a Shipyard class with a static buildShip(type, name) method.
  • The factory should handle three types:
    • 'scout': Low firepower (10), high shield strength (50).
    • 'destroyer': High firepower (100), medium shield strength (40).
    • 'carrier': Medium firepower (50), high shield strength (80).
  • The returned object should include a method called statusReport() that logs the ship's name and its combat stats to the console.
  • If an invalid type is passed, the factory should return a basic 'debris' object with 0 stats.

Test your factory by creating one of each ship type and calling their statusReport() methods.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.