Factory Method Pattern

Site Admin · 11 Sep 2026 · 11 views

The Factory Method Pattern

The Factory Method pattern defines an interface for creating an object, but lets a parameter or subclass decide which class to instantiate. Instead of calling a constructor directly, your code calls a factory method that returns the right object. This decouples creation logic from business logic.

The Problem It Solves

Imagine a notification system. The type of notification (email, SMS, push) is known only at runtime from user preferences. Writing new EmailNotification() everywhere couples your code to one implementation. Adding a new type would force you to hunt down and change every call site.

+----------------+   create(type)   +---------------------+
|   Client code  | ---------------> |  NotificationFactory|
+----------------+                  +---------------------+
                                            |     |     |
                              +-------------+     |     +--------------+
                              |                  |                    |
                              >                  >                    >
                    +-----------------+  +---------------+  +-----------------+
                    |EmailNotification|  |SMSNotification|  |PushNotification|
                    +-----------------+  +---------------+  +-----------------+

The client knows only Notification and NotificationFactory; the concrete class is chosen at runtime.

Ingredients

Java has no free functions, so a factory is usually a static method in a class. Start with the product interface and concrete implementations.

public interface Notification {
    void send(String message);
}

public class EmailNotification implements Notification {
    public void send(String message) {
        System.out.println("Email: " + message);
    }
}

public class SMSNotification implements Notification {
    public void send(String message) {
        System.out.println("SMS: " + message);
    }
}

public class PushNotification implements Notification {
    public void send(String message) {
        System.out.println("Push: " + message);
    }
}

Each class implements the Notification contract, so callers depend only on the interface.

The Factory Method

The factory method accepts a type and returns the matching implementation.

public class NotificationFactory {

    public static Notification create(String type) {
        switch (type.toLowerCase()) {
            case "email":
                return new EmailNotification();
            case "sms":
                return new SMSNotification();
            case "push":
                return new PushNotification();
            default:
                throw new IllegalArgumentException("Unknown type: " + type);
        }
    }
}

// Usage - the service never instantiates a concrete class
public class NotificationService {
    public void sendNotification(String type, String message) {
        Notification notification = NotificationFactory.create(type);
        notification.send(message);
    }
}

Walkthrough: create() reads the type string, matches it in the switch, and returns the correct Notification. The service then sends through the interface. Adding a channel means one new class plus one new case in the factory - the service stays untouched, honoring the Open/Closed Principle.

Real-World Example: Logger

Logging frameworks select console, file, or database loggers through factories. Java itself uses Factory Methods in Calendar.getInstance() and DriverManager.getConnection().

public interface Logger {
    void log(String level, String message);
}

public class ConsoleLogger implements Logger {
    public void log(String level, String message) {
        System.out.println("[" + level + "] " + message);
    }
}

public class FileLogger implements Logger {
    private final String filePath;

    public FileLogger(String filePath) {
        this.filePath = filePath;
    }

    public void log(String level, String message) {
        // append to file
    }
}

public class LoggerFactory {
    public static Logger create(String type) {
        switch (type) {
            case "console":
                return new ConsoleLogger();
            case "file":
                return new FileLogger("/var/log/app.log");
            default:
                throw new IllegalArgumentException("Unknown logger");
        }
    }
}

FileLogger also shows that factories can pass configuration arguments to constructors, hiding that complexity from the caller.

Key Points

  • Factory Method defines an interface for creating objects but lets a type or subclass decide the concrete class.
  • It decouples creation logic from business logic, making code easier to extend.
  • The factory returns an interface type, never a concrete class.
  • Adding a type means one new class and one new case - existing code stays untouched.
  • Widely used in the Java standard library for connection and service creation.
Share this post:

Comments (0)

Please login or register to comment.