> For the complete documentation index, see [llms.txt](https://mayanktyagi3111.gitbook.io/interview-prep/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mayanktyagi3111.gitbook.io/interview-prep/lld-questions/meeting-scheduler.md).

# Meeting Scheduler

### **🔹 Overview**

A **Meeting Scheduler** system allows users to **schedule, cancel, and manage meetings** while ensuring no conflicts arise. The system also supports features like **meeting reminders, notifications, and undo/redo operations**.

***

### **🔹 Design Patterns Used**

#### **1️⃣ Singleton Pattern**

* Ensures only **one instance** of `MeetingScheduler` exists.
* Centralized meeting management.

#### **2️⃣ Factory Pattern**

* **Encapsulates object creation** for different meeting types (`Virtual`, `In-Person`).
* Supports scalability when adding new meeting types.

#### **3️⃣ Observer Pattern**

* **Notifies users** when a meeting is scheduled or canceled.

#### **4️⃣ Strategy Pattern**

* **Handles conflict resolution strategies** dynamically.

#### **5️⃣ Decorator Pattern**

* **Adds meeting reminders dynamically** without modifying existing meeting classes.

#### **6️⃣ Command Pattern**

* Supports **undo/redo** functionality for meeting scheduling and cancellation.

***

## **🔹 Complete Java Implementation**

```java
import java.time.LocalDateTime;
import java.util.*;

// ==================== Singleton Pattern (MeetingScheduler) ====================
class MeetingScheduler {
    private static MeetingScheduler instance;
    private List<Meeting> meetings;
    private CommandHistory commandHistory;

    private MeetingScheduler() {
        meetings = new ArrayList<>();
        commandHistory = new CommandHistory();
    }

    public static synchronized MeetingScheduler getInstance() {
        if (instance == null) {
            instance = new MeetingScheduler();
        }
        return instance;
    }

    public boolean scheduleMeeting(Meeting meeting) {
        if (!isConflict(meeting)) {
            meetings.add(meeting);
            meeting.notifyObservers();
            commandHistory.executeCommand(new ScheduleMeetingCommand(this, meeting));
            return true;
        }
        return false;
    }

    public void cancelMeeting(Meeting meeting) {
        meetings.remove(meeting);
        System.out.println("Meeting '" + meeting.getTitle() + "' has been cancelled.");
        commandHistory.executeCommand(new CancelMeetingCommand(this, meeting));
    }

    public void undoLastAction() {
        commandHistory.undo();
    }

    private boolean isConflict(Meeting newMeeting) {
        for (Meeting meeting : meetings) {
            if (meeting.conflictsWith(newMeeting)) {
                return true;
            }
        }
        return false;
    }
}

// ==================== Observer Pattern (User) ====================
interface Observer {
    void update(Meeting meeting);
}

class User implements Observer {
    private int id;
    private String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public void update(Meeting meeting) {
        System.out.println("Notification: " + name + ", your meeting '" + meeting.getTitle() + "' is scheduled.");
    }

    public String getName() {
        return name;
    }
}

// ==================== Factory Pattern (Meeting Factory) ====================
abstract class Meeting {
    protected int id;
    protected String title;
    protected TimeSlot timeSlot;
    protected List<User> participants;
    private List<Observer> observers;

    public Meeting(int id, String title, TimeSlot timeSlot) {
        this.id = id;
        this.title = title;
        this.timeSlot = timeSlot;
        this.participants = new ArrayList<>();
        this.observers = new ArrayList<>();
    }

    public void addParticipant(User user) {
        participants.add(user);
        observers.add(user);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(this);
        }
    }

    public boolean conflictsWith(Meeting other) {
        return this.timeSlot.overlapsWith(other.timeSlot);
    }

    public String getTitle() {
        return title;
    }
}

// ==================== Concrete Meeting Types ====================
class InPersonMeeting extends Meeting {
    private String location;

    public InPersonMeeting(int id, String title, TimeSlot timeSlot, String location) {
        super(id, title, timeSlot);
        this.location = location;
    }
}

class VirtualMeeting extends Meeting {
    private String meetingLink;

    public VirtualMeeting(int id, String title, TimeSlot timeSlot, String meetingLink) {
        super(id, title, timeSlot);
        this.meetingLink = meetingLink;
    }
}

class MeetingFactory {
    public static Meeting createMeeting(String type, int id, String title, TimeSlot timeSlot, String extraDetail) {
        if (type.equalsIgnoreCase("inperson")) {
            return new InPersonMeeting(id, title, timeSlot, extraDetail);
        } else if (type.equalsIgnoreCase("virtual")) {
            return new VirtualMeeting(id, title, timeSlot, extraDetail);
        }
        throw new IllegalArgumentException("Invalid meeting type: " + type);
    }
}

// ==================== Decorator Pattern (Meeting Reminders) ====================
abstract class MeetingDecorator extends Meeting {
    protected Meeting decoratedMeeting;

    public MeetingDecorator(Meeting meeting) {
        super(meeting.id, meeting.title, meeting.timeSlot);
        this.decoratedMeeting = meeting;
    }

    public abstract void addFeature();
}

class MeetingWithReminder extends MeetingDecorator {
    private int reminderMinutesBefore;

    public MeetingWithReminder(Meeting meeting, int reminderMinutesBefore) {
        super(meeting);
        this.reminderMinutesBefore = reminderMinutesBefore;
    }

    @Override
    public void addFeature() {
        System.out.println("Reminder set: " + reminderMinutesBefore + " minutes before the meeting.");
    }
}

// ==================== Command Pattern (Undo/Redo) ====================
interface Command {
    void execute();
    void undo();
}

class ScheduleMeetingCommand implements Command {
    private MeetingScheduler scheduler;
    private Meeting meeting;

    public ScheduleMeetingCommand(MeetingScheduler scheduler, Meeting meeting) {
        this.scheduler = scheduler;
        this.meeting = meeting;
    }

    @Override
    public void execute() {
        scheduler.scheduleMeeting(meeting);
    }

    @Override
    public void undo() {
        scheduler.cancelMeeting(meeting);
    }
}

class CancelMeetingCommand implements Command {
    private MeetingScheduler scheduler;
    private Meeting meeting;

    public CancelMeetingCommand(MeetingScheduler scheduler, Meeting meeting) {
        this.scheduler = scheduler;
        this.meeting = meeting;
    }

    @Override
    public void execute() {
        scheduler.cancelMeeting(meeting);
    }

    @Override
    public void undo() {
        scheduler.scheduleMeeting(meeting);
    }
}

class CommandHistory {
    private Stack<Command> history = new Stack<>();

    public void executeCommand(Command command) {
        command.execute();
        history.push(command);
    }

    public void undo() {
        if (!history.isEmpty()) {
            Command lastCommand = history.pop();
            lastCommand.undo();
        }
    }
}

// ==================== TimeSlot ====================
class TimeSlot {
    private LocalDateTime startTime;
    private LocalDateTime endTime;

    public TimeSlot(LocalDateTime startTime, LocalDateTime endTime) {
        this.startTime = startTime;
        this.endTime = endTime;
    }

    public boolean overlapsWith(TimeSlot other) {
        return startTime.isBefore(other.endTime) && endTime.isAfter(other.startTime);
    }
}

// ==================== Main Class (Testing) ====================
public class Main {
    public static void main(String[] args) {
        MeetingScheduler scheduler = MeetingScheduler.getInstance();

        User alice = new User(1, "Alice");
        User bob = new User(2, "Bob");

        TimeSlot timeSlot1 = new TimeSlot(LocalDateTime.of(2025, 3, 10, 10, 0), LocalDateTime.of(2025, 3, 10, 11, 0));

        Meeting meeting1 = MeetingFactory.createMeeting("virtual", 101, "Project Kickoff", timeSlot1, "zoom.com/meeting1");
        meeting1.addParticipant(alice);
        meeting1.addParticipant(bob);

        Meeting meetingWithReminder = new MeetingWithReminder(meeting1, 15);
        ((MeetingWithReminder) meetingWithReminder).addFeature();

        if (scheduler.scheduleMeeting(meeting1)) {
            System.out.println("Meeting scheduled successfully.");
        }

        scheduler.undoLastAction();
    }
}
```

***

### **✅ Final Features**

✅ **Decorator Pattern** → Add reminders dynamically.\
✅ **Command Pattern** → Supports **Undo/Redo** actions.\
✅ **Factory Pattern** → Encapsulated object creation.

**Would you like further refinements? 🚀**
