Factory Method Pattern with Registry
Implement the Factory pattern using a registry map for extensible object creation without switch statements.
import java.util.*;
import java.util.function.Supplier;
// Product interface
interface Notification {
void send(String to, String message);
}
// Concrete products
class EmailNotification implements Notification {
public void send(String to, String message) {
System.out.printf("EMAIL to %s: %s%n", to, message);
}
}
class SmsNotification implements Notification {
public void send(String to, String message) {
System.out.printf("SMS to %s: %s%n", to, message);
}
}
class SlackNotification implements Notification {
public void send(String to, String message) {
System.out.printf("SLACK to #%s: %s%n", to, message);
}
}
// Factory with registry
class NotificationFactory {
private static final Map<String, Supplier<Notification>> registry = new HashMap<>();
static {
registry.put("email", EmailNotification::new);
registry.put("sms", SmsNotification::new);
registry.put("slack", SlackNotification::new);
}
// Register new types at runtime
public static void register(String type, Supplier<Notification> creator) {
registry.put(type.toLowerCase(), creator);
}
public static Notification create(String type) {
Supplier<Notification> creator = registry.get(type.toLowerCase());
if (creator == null) {
throw new IllegalArgumentException("Unknown notification type: " + type);
}
return creator.get();
}
public static Set<String> availableTypes() {
return Collections.unmodifiableSet(registry.keySet());
}
}
public class FactoryDemo {
public static void main(String[] args) {
Notification n = NotificationFactory.create("email");
n.send("alice@test.com", "Hello from factory!");
// Register custom type
NotificationFactory.register("webhook", () -> (to, msg) ->
System.out.printf("WEBHOOK %s: %s%n", to, msg));
NotificationFactory.create("webhook").send("url", "Custom!");
System.out.println("Types: " + NotificationFactory.availableTypes());
}
}Use Cases
- Extensible object creation in plugin architectures
- Decoupling client code from concrete implementations
- Service provider pattern for notifications or parsers
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Builder Pattern — Fluent Object Construction
Implement the Builder pattern for complex objects with validation, immutability, and method chaining.
Best for: Constructing complex objects with many optional parameters
Singleton Pattern — Thread-Safe Approaches
Implement thread-safe singletons in Java: enum, holder class, double-checked locking, and eager init.
Best for: Application-wide configuration managers
Strategy Pattern with Lambdas
Implement the Strategy pattern using interfaces and Java lambdas for flexible algorithm selection.
Best for: Swappable pricing or discount algorithms
Observer Pattern — Event System
Build a type-safe event system using the Observer pattern with generics and functional interfaces.
Best for: Decoupled event-driven architectures