DEV Community

NOOB
NOOB

Posted on

LLD-10: Notification System

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 new keyword 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()|
+---------------------+    +---------------------+    +---------------------+
Enter fullscreen mode Exit fullscreen mode

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

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

  1. Interface (Notification): Defines the sendNotification() contract all channels must follow
  2. Concrete Classes: Each class implements its own channel-specific delivery logic
  3. Factory (NotificationFactory): Takes a NotificationType Enum and returns the right object
  4. Client (main): Only talks to the factory and the interface — never touches concrete classes directly

Sample Output

Top comments (0)