Back to all terms
S1S2
State & Archbasic

Factory Pattern

A creational design pattern that encapsulates object creation logic, allowing the client to request objects without knowing the concrete class or complex construction details.

Also known as: Factory Method, Abstract Factory, Object Factory, Creator Pattern

Description

The Factory pattern encapsulates the logic for creating objects, decoupling the client code from the specific classes it needs to instantiate. Instead of calling new ConcreteClass() directly, the client calls a factory method or class that determines the correct type to create based on parameters, configuration, or runtime conditions. This enables the Open-Closed Principle: new types can be added by extending the factory without modifying client code.

The pattern comes in several variants. The Simple Factory is a function or static method that returns different types based on input: createNotification('email') returns EmailNotification while createNotification('sms') returns SmsNotification. The Factory Method defines an interface for creating objects but lets subclasses decide which class to instantiate. The Abstract Factory provides an interface for creating families of related objects—a UIFactory that produces Button, TextField, and Modal components styled consistently for a given theme or platform.

In TypeScript/JavaScript applications, factories are especially common for: creating database connections based on environment configuration, constructing complex objects with many optional parameters (builder pattern variant), instantiating strategy objects based on runtime conditions, and creating test fixtures with sensible defaults (factory-bot pattern). The factory pattern pairs naturally with dependency injection—a DI container is essentially a sophisticated factory that resolves dependency graphs automatically. The anti-pattern to avoid is the God Factory that creates everything in the application, violating the Single Responsibility Principle.

Prompt Snippet

Implement a PaymentProcessorFactory that returns the correct PaymentProcessor implementation (StripeProcessor, PayPalProcessor, BraintreeProcessor) based on the tenant's configuration stored in the database. Define the factory as a class registered in the tsyringe DI container that receives all processor implementations and a TenantConfigRepository. Use a Map<PaymentProvider, new (...args) => PaymentProcessor> for registration to ensure type safety and O(1) lookup. For tests, create a TestPaymentProcessorFactory that returns an InMemoryPaymentProcessor recording all calls for assertion. Include a factory method createFromConfig(config: TenantConfig): PaymentProcessor that validates the config and throws a descriptive DomainError if the requested provider is not registered.

Tags

design-patternscreationalgang-of-foursolid-principlesobject-oriented