Factory Method Pattern in Java: Delegating Object Creation
The Problem
You need to create objects, but the exact type to instantiate should be decided by subclasses or configuration — not hardcoded with new. The Factory Method pattern defines an interface for creating an object, letting subclasses decide which class to instantiate.
Diagram
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor': '#eef2ff', 'primaryTextColor': '#1e293b', 'primaryBorderColor': '#818cf8', 'lineColor': '#94a3b8', 'secondaryColor': '#f0fdf4', 'secondaryBorderColor': '#86efac', 'tertiaryColor': '#fff7ed', 'tertiaryBorderColor': '#fdba74', 'background': '#ffffff', 'mainBkg': '#eef2ff', 'secondBkg': '#f0fdf4', 'tertiaryBkg': '#fff7ed', 'noteBkgColor': '#fff7ed', 'noteBorderColor': '#fdba74', 'actorBkg': '#eef2ff', 'actorBorder': '#818cf8' }}}%%
classDiagram
class NotificationCreator {
<<abstract>>
+createNotification() Notification
+send(String message)
}
class EmailNotificationCreator {
+createNotification() Notification
}
class SmsNotificationCreator {
+createNotification() Notification
}
class Notification {
<<interface>>
+deliver(String message)
}
class EmailNotification
class SmsNotification
NotificationCreator <|-- EmailNotificationCreator
NotificationCreator <|-- SmsNotificationCreator
NotificationCreator ..> Notification : creates
Notification <|.. EmailNotification
Notification <|.. SmsNotificationJava Example
public interface Notification {
void deliver(String message);
}
public class EmailNotification implements Notification {
public void deliver(String message) {
System.out.println("Email: " + message);
}
}
public class SmsNotification implements Notification {
public void deliver(String message) {
System.out.println("SMS: " + message);
}
}
public abstract class NotificationCreator {
protected abstract Notification createNotification();
public void send(String message) {
Notification notification = createNotification();
notification.deliver(message);
}
}
public class EmailNotificationCreator extends NotificationCreator {
protected Notification createNotification() {
return new EmailNotification();
}
}
public class SmsNotificationCreator extends NotificationCreator {
protected Notification createNotification() {
return new SmsNotification();
}
}Quarkus Example
@ApplicationScoped
public class NotificationFactory {
@Inject
@ConfigProperty(name = "notification.channel", defaultValue = "email")
String channel;
@Produces
@ApplicationScoped
public Notification notification() {
return switch (channel) {
case "sms" -> new SmsNotification();
default -> new EmailNotification();
};
}
}In Quarkus, Factory Method often becomes a CDI @Produces method, letting the container pick the implementation based on configuration:
Any bean can then simply @Inject Notification notification; without knowing which concrete implementation is active — Quarkus resolves it from application.properties.
Key Takeaways
- Use Factory Method when a class can’t anticipate which concrete type it needs to create.
- It keeps client code decoupled from concrete classes, easing testing and extension.
- In Quarkus,
@Producesmethods and CDI qualifiers are a natural, idiomatic replacement for manual factory hierarchies — very common in TMF-style multitenant systems where the implementation varies per tenant or channel.

