Skip to main content

The Factory Method Pattern

Category: Creational

The Factory Method 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 the new operator directly in your business logic (which tightly couples your code to a specific class), you call a special "Factory" method. This method is responsible for instantiating the correct object and returning it.


When to use the Factory Pattern?

  • When you don't know beforehand the exact types and dependencies of the objects your code should work with.
  • When you want to centralize the object creation logic in one place, making the system easier to maintain and extend.

Example: The Notification System

Imagine you are building a system that sends notifications. Right now, it only sends SMS. But in the future, you know you will need to add Email and Push notifications.

If you hardcode new SMSNotification() everywhere in your app, adding a new notification type later will require changing hundreds of files. Let's use a Factory instead!

1. Create the Common Interface

All products created by the factory must implement the same interface.

public interface Notification {
void notifyUser();
}

2. Create the Concrete Implementations

public class SMSNotification implements Notification {

@Override
public void notifyUser() {
System.out.println("Sending an SMS notification...");
}
}

public class EmailNotification implements Notification {

@Override
public void notifyUser() {
System.out.println("Sending an Email notification...");
}
}

3. Create the Factory Class

This class contains the logic to create the correct object based on some input (like a string or an enum).

public class NotificationFactory {

// The Factory Method
public Notification createNotification(String channel) {
if (channel == null || channel.isEmpty()) {
return null;
}

switch (channel.toUpperCase()) {
case "SMS":
return new SMSNotification();
case "EMAIL":
return new EmailNotification();
default:
throw new IllegalArgumentException("Unknown channel: " + channel);
}
}
}

4. Client Code

Notice how the client code doesn't use the new keyword for the notifications, and doesn't even care how the SMSNotification or EmailNotification is instantiated!

public class LabFactory1 {

public static void main(String[] args) {
NotificationFactory factory = new NotificationFactory();

// We just ask the factory for an SMS notification
Notification notification1 = factory.createNotification("SMS");
notification1.notifyUser();

// We ask for an Email notification
Notification notification2 = factory.createNotification("EMAIL");
notification2.notifyUser();
}
}

[!NOTE] This specific implementation is often called the Simple Factory. The true "Factory Method" pattern goes a step further by making the Factory class itself an interface, and having concrete factories (e.g., SMSFactory, EmailFactory) implement the creation logic. However, the Simple Factory shown above is the most commonly used variation in everyday Java development.