Notification System - Factory Pattern Implementation
This is an implementation of the Factory design pattern for a multi-channel notification system where the client remains completely decoupled from the concrete notification classes being created.
Problem Statement
Building a fintech alert system that can send notifications through multiple channels (Email, WhatsApp, Instagram). The challenge is to centralize object creation so the client code never needs to know which concrete class is being instantiated.
Key Challenge:
- Support multiple notification channels
- Client must remain ignorant of concrete classes
- The
newkeyword should only appear in one place — the Factory - Adding new notification channels should not require changes to client code
Class Diagram
+----------------------+
| NotificationFactory |
+----------------------+
| + getNotification() |
+----------+-----------+
|
| (Creates)
v
+----------------------+
| Notification |
| (Interface) |
+----------------------+
| + sendNotification() |
+----------+-----------+
^
| (Implements)
+--------------------------+--------------------------+
| | |
+----------+----------+ +----------+----------+ +----------+----------+
| EmailNotification | | WhatsAppNotification| |InstagramNotification|
+---------------------+ +---------------------+ +---------------------+
| + sendNotification()| | + sendNotification()| | + sendNotification()|
+---------------------+ +---------------------+ +---------------------+
Implementation
package factory.notificationsystem;
public class NotificationSystem {
/**
* Enum to define supported notification channels.
* Ensures type safety and prevents invalid string inputs.
*/
enum NotificationType {
EMAIL,
WHATSAPP,
INSTAGRAM
}
/**
* Component Interface.
* Defines the contract all notification channels must follow.
*/
interface Notification {
void sendNotification(String notification);
}
/**
* Concrete Class for Email Notifications.
*/
static class EmailNotification implements Notification {
@Override
public void sendNotification(String notification) {
System.out.println("[NOTIFICATION: EMAIL] " + notification);
}
}
/**
* Concrete Class for WhatsApp Notifications.
*/
static class WhatsAppNotification implements Notification {
@Override
public void sendNotification(String notification) {
System.out.println("[NOTIFICATION: WHATSAPP] " + notification);
}
}
/**
* Concrete Class for Instagram Notifications.
*/
static class InstagramNotification implements Notification {
@Override
public void sendNotification(String notification) {
System.out.println("[NOTIFICATION: INSTAGRAM] " + notification);
}
}
/**
* The Factory Class.
* This is the ONLY place where the new keyword is used to
* instantiate concrete notification classes.
* The client remains completely ignorant of which class is created.
*/
static class NotificationFactory {
public Notification getNotification(NotificationType notificationType) {
return switch (notificationType) {
case EMAIL -> new EmailNotification();
case WHATSAPP -> new WhatsAppNotification();
case INSTAGRAM -> new InstagramNotification();
default -> throw new IllegalArgumentException(
"Unsupported Notification Type"
);
};
}
}
/**
* Main driver method.
* The client only interacts with the Factory and the Interface.
* It never references EmailNotification, WhatsAppNotification, etc. directly.
*/
public static void main(String[] args) {
System.out.println("---- Fintech Alert System ----");
NotificationFactory notificationFactory = new NotificationFactory();
Notification emailAlert = notificationFactory.getNotification(
NotificationType.EMAIL
);
emailAlert.sendNotification("Hello from EMAIL");
Notification whatsAppAlert = notificationFactory.getNotification(
NotificationType.WHATSAPP
);
whatsAppAlert.sendNotification("Hello from WhatsApp");
Notification instagramAlert = notificationFactory.getNotification(
NotificationType.INSTAGRAM
);
instagramAlert.sendNotification("Hello from Instagram");
}
}
Key Features
- Factory Pattern: Centralizes object creation in a single place
- Type Safety: Uses Enum instead of raw strings for notification types
- Loose Coupling: Client only depends on the interface, never on concrete classes
- Single Responsibility: Factory handles creation, concrete classes handle delivery
- Open/Closed Principle: Add new channels without modifying existing code
- Extensible: New notification types require only a new class and a new Enum value
How It Works
-
Interface (Notification): Defines the
sendNotification()contract all channels must follow - Concrete Classes: Each class implements its own channel-specific delivery logic
-
Factory (NotificationFactory): Takes a
NotificationTypeEnum and returns the right object - Client (main): Only talks to the factory and the interface — never touches concrete classes directly
Top comments (0)