Creational Pattern

Factory Method Pattern

Define an interface for creating objects, but let subclasses decide which class to instantiate. Factory Method defers instantiation to subclasses.

12 min readHigh Priority

1What is Factory Method?

Real-World Analogy
Hiring Agency

A company needs employees but doesn't directly hire them. They use an agency (factory) that creates the right type of employee (developer, designer, manager) based on requirements.

Pizza Store

A pizza store chain has the same ordering process, but each location creates different pizza styles (NY style, Chicago style). The "create pizza" step is delegated to each store.

Factory Method is a creational pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. It promotes loose coupling by eliminating the need to bind application-specific classes into your code.

Factory Method Structure

<<interface>>ProductConcreteProductAConcreteProductB<<abstract>>Creator+ factoryMethod(): ProductConcreteCreatorAConcreteCreatorBcreates
Creator defines factory method. Concrete creators return specific product types.

2Simple Factory vs Factory Method

These are often confused. Here's the key difference:

Simple Factory
class ShapeFactory {
  static create(type) {
    if (type == "circle") 
      return new Circle();
    if (type == "square") 
      return new Square();
  }
}
  • • Single class with creation logic
  • • Uses conditionals (if/switch)
  • • Not a GoF pattern (idiom)
  • • Violates Open/Closed on addition
Factory Method
abstract class ShapeFactory {
  abstract create(): Shape;
}
class CircleFactory extends ... {
  create() { return new Circle(); }
}
class SquareFactory extends ... {
  create() { return new Square(); }
}
  • • Subclasses decide what to create
  • • Uses inheritance/polymorphism
  • • GoF design pattern
  • • Open/Closed compliant

3Implementation

Factory Method - Notification System
// ========== Product Interface ==========
interface Notification {
    void send(String message);
}

// ========== Concrete Products ==========
class EmailNotification implements Notification {
    private String email;
    
    public EmailNotification(String email) {
        this.email = email;
    }
    
    @Override
    public void send(String message) {
        System.out.println("Email to " + email + ": " + message);
    }
}

class SMSNotification implements Notification {
    private String phone;
    
    public SMSNotification(String phone) {
        this.phone = phone;
    }
    
    @Override
    public void send(String message) {
        System.out.println("SMS to " + phone + ": " + message);
    }
}

class PushNotification implements Notification {
    private String deviceId;
    
    public PushNotification(String deviceId) {
        this.deviceId = deviceId;
    }
    
    @Override
    public void send(String message) {
        System.out.println("Push to " + deviceId + ": " + message);
    }
}

// ========== Creator (Factory) ==========
abstract class NotificationFactory {
    // Factory Method - subclasses override this
    protected abstract Notification createNotification(String recipient);
    
    // Template method that uses the factory method
    public void notify(String recipient, String message) {
        Notification notification = createNotification(recipient);
        notification.send(message);
    }
}

// ========== Concrete Creators ==========
class EmailNotificationFactory extends NotificationFactory {
    @Override
    protected Notification createNotification(String recipient) {
        return new EmailNotification(recipient);
    }
}

class SMSNotificationFactory extends NotificationFactory {
    @Override
    protected Notification createNotification(String recipient) {
        return new SMSNotification(recipient);
    }
}

class PushNotificationFactory extends NotificationFactory {
    @Override
    protected Notification createNotification(String recipient) {
        return new PushNotification(recipient);
    }
}

// ========== Usage ==========
public class Main {
    public static void main(String[] args) {
        NotificationFactory factory;
        
        // Client code doesn't know which concrete class is used
        factory = new EmailNotificationFactory();
        factory.notify("user@email.com", "Your order shipped!");
        
        factory = new SMSNotificationFactory();
        factory.notify("+1234567890", "Your OTP is 123456");
        
        factory = new PushNotificationFactory();
        factory.notify("device-abc-123", "New message received");
    }
}
Output:
Email to user@email.com: Your order shipped!
SMS to +1234567890: Your OTP is 123456
Push to device-abc-123: New message received

4When to Use Factory Method

Use When
  • Don't know exact types beforehand
  • Want to extend library/framework
  • Reuse existing objects (pooling)
  • Complex object creation logic
Avoid When
  • Simple object creation suffices
  • Types are known and fixed
  • Adds unnecessary complexity
  • Few product types unlikely to change
Real-World Examples
  • Java: Calendar.getInstance(), NumberFormat.getInstance()
  • Loggers: LoggerFactory.getLogger()
  • UI Frameworks: Button factories creating OS-specific buttons
  • Document Apps: Creating different document types (Word, PDF)

5Interview Follow-up Questions

Interview Follow-up Questions

Common follow-up questions interviewers ask

6Key Takeaways

1Factory Method lets subclasses decide which class to instantiate.
2Different from Simple Factory which uses conditionals.
3Follows Open/Closed - add types without modifying code.
4Use when: unknown types, framework extension, complex creation.
5Creator defines factory method, concrete creators override it.
6Related: Abstract Factory (families), Builder (complex objects).