Factory Pattern

⭐ Interview Importance: HIGH
⏱️ Revision Time: 1 min

Concept

Category: Creational Pattern

The Factory Pattern provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.

Instead of calling new Car() directly in your business logic, you ask a “Factory” to make the car for you: CarFactory.createCar('Tesla').

Why? If the process of building a Car requires 50 lines of complex setup (injecting engines, painting, attaching tires), you do not want to duplicate those 50 lines everywhere in your codebase. You abstract the complex creation logic into a centralized Factory.

The Mental Model

Imagine a Logistics App. Your app calculates routes for Trucks.
Months later, your app is a massive success, and you want to add sea logistics (Ships).
If your entire codebase is tightly coupled to new Truck(), you have to tear apart the entire application and add if (type === 'sea') new Ship() in 100 different files.

If you used a Factory, your codebase just asks TransportFactory.createTransport(type). When you add Ships, you only update the Factory file. The rest of the codebase doesn’t care; it just receives a Transport object and tells it to deliver().

Implementation (Simple Factory)

// 1. Define a common interface for all products
interface Transport {
    deliver(): void;
}

// 2. Create the concrete products
class Truck implements Transport {
    deliver() {
        console.log("Delivering cargo by land in a box.");
    }
}

class Ship implements Transport {
    deliver() {
        console.log("Delivering cargo by sea in a container.");
    }
}

// 3. Create the Factory!
class TransportFactory {
    // The Factory encapsulates the IF/ELSE logic of creation
    public static createTransport(type: "road" | "sea"): Transport {
        if (type === "road") {
            // Complex Truck assembly logic goes here
            return new Truck();
        } else if (type === "sea") {
            // Complex Ship assembly logic goes here
            return new Ship();
        }
        throw new Error("Unknown transport type.");
    }
}

// Usage:
// The client doesn't need to know HOW the objects are built!
const landLogistics = TransportFactory.createTransport("road");
landLogistics.deliver(); // "Delivering cargo by land..."

const seaLogistics = TransportFactory.createTransport("sea");
seaLogistics.deliver(); // "Delivering cargo by sea..."

The Abstract Factory (The Upgrade)

The standard Factory creates one family of products (Transports).
What if you are building a GUI framework, and you need to generate Buttons, Checkboxes, and Scrollbars?
What if the user clicks “Dark Mode”? You need to instantly switch to creating DarkButtons, DarkCheckboxes, and DarkScrollbars.

An Abstract Factory is a “Factory of Factories”.
You create a GUIFactory interface.
You then build a LightModeFactory and a DarkModeFactory.
When the app launches, you inject the correct Factory into the application. The application just blindly calls factory.createButton(), and it flawlessly generates the correct theme without a single if (theme === 'dark') check in the UI code!

Interview Questions

Q: Does the Factory Pattern violate the Open/Closed Principle?
A: The “Simple Factory” (the if/else switch statement shown above) technically violates the Open/Closed Principle because every time you add a new vehicle (like Airplane), you must physically open the TransportFactory class and modify its internal code.
To achieve pure SOLID compliance, you upgrade to the Factory Method Pattern, where you define an abstract Logistics class, and create concrete RoadLogistics and SeaLogistics subclasses that each override the createTransport() method. This allows you to add AirLogistics without ever touching the existing code!

Q: In React, what is the equivalent of a Factory?
A: In React, a component that returns different UI elements based on props is fundamentally a Factory!

function ButtonFactory({ type }) {
    if (type === 'primary') return <PrimaryButton />;
    if (type === 'danger') return <DangerButton />;
    return <DefaultButton />;
}

This is the exact same architectural concept, just implemented in functional JSX instead of Object-Oriented classes.