> 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/multi-tier-elevator-system.md).

# Multi-Tier Elevator System

#### Multi-Tier Elevator System: Low-Level Design (LLD) with Java Code and Design Patterns

In this answer, we will design a **Multi-Tier Elevator System** for a building with multiple floors and several elevators. The design will include various OOD patterns such as **Strategy Pattern** for elevator movement, **Command Pattern** for processing requests, and **Factory Pattern** for creating elevator instances. Additionally, we'll discuss algorithms like **FIFO (First-In, First-Out)**, **SCAN**, and **Priority Weight** for elevator request scheduling.

***

#### **Design Overview**

In a **Multi-Tier Elevator System**, we need to manage elevators that move between floors based on requests from passengers. The system should be capable of managing multiple elevators and handling requests efficiently while ensuring that requests are processed in an optimized way.

Key components of the system:

1. **Elevator**: Represents an elevator that moves between floors.
2. **Floor**: Represents a floor in the building.
3. **Request**: Represents a request made by a passenger to either go up or down to a specific floor.
4. **ElevatorControlSystem**: Manages multiple elevators and processes requests.
5. **Scheduler**: Schedules the request processing using different algorithms.
6. **MovementStrategy**: Provides different movement strategies for elevators.
7. **Command**: Represents an action to be performed on the elevator system (e.g., request handling).

We will use the following design patterns:

* **Strategy Pattern** for elevator movement algorithms.
* **Command Pattern** for processing requests.
* **Factory Pattern** for creating different types of elevator instances.
* **Observer Pattern** for notifying passengers when their requested elevator arrives.

***

#### **Classes and Data Structures**

**1. Elevator Class**

The **Elevator** class represents the elevator that moves between floors.

```java
class Elevator {
    private int currentFloor;
    private boolean isMoving;
    private Direction direction;
    private final int id;

    public enum Direction {
        UP, DOWN, NONE
    }

    public Elevator(int id) {
        this.currentFloor = 0; // Ground floor
        this.isMoving = false;
        this.direction = Direction.NONE;
        this.id = id;
    }

    public int getCurrentFloor() {
        return currentFloor;
    }

    public void moveTo(int floor) {
        this.isMoving = true;
        if (currentFloor < floor) {
            direction = Direction.UP;
        } else {
            direction = Direction.DOWN;
        }
        // Simulate movement by changing the floor number.
        this.currentFloor = floor;
        this.isMoving = false;
        System.out.println("Elevator " + id + " arrived at floor " + floor);
    }

    public Direction getDirection() {
        return direction;
    }
    
    public boolean isMoving() {
        return isMoving;
    }
}
```

**2. Request Class**

The **Request** class represents a request to move an elevator to a specific floor.

```java
class Request {
    private int targetFloor;
    private int requestTime; // Time when the request was made (used for FIFO algorithm).

    public Request(int targetFloor, int requestTime) {
        this.targetFloor = targetFloor;
        this.requestTime = requestTime;
    }

    public int getTargetFloor() {
        return targetFloor;
    }

    public int getRequestTime() {
        return requestTime;
    }
}
```

**3. Scheduler Class (Strategy Pattern)**

The **Scheduler** class decides which algorithm to use for processing elevator requests. We will use a **Strategy Pattern** to allow dynamic selection of different algorithms (FIFO, SCAN, Priority-based).

```java
interface RequestSchedulingStrategy {
    void scheduleRequest(List<Request> requests, List<Elevator> elevators);
}

class FIFOScheduler implements RequestSchedulingStrategy {
    @Override
    public void scheduleRequest(List<Request> requests, List<Elevator> elevators) {
        requests.sort(Comparator.comparingInt(Request::getRequestTime)); // FIFO by request time
        processRequests(requests, elevators);
    }

    private void processRequests(List<Request> requests, List<Elevator> elevators) {
        for (Request request : requests) {
            Elevator selectedElevator = selectElevatorForRequest(request, elevators);
            selectedElevator.moveTo(request.getTargetFloor());
        }
    }

    private Elevator selectElevatorForRequest(Request request, List<Elevator> elevators) {
        // Simple heuristic: Choose the closest elevator
        return elevators.stream().min(Comparator.comparingInt(elevator -> Math.abs(elevator.getCurrentFloor() - request.getTargetFloor()))).get();
    }
}

class SCANScheduler implements RequestSchedulingStrategy {
    @Override
    public void scheduleRequest(List<Request> requests, List<Elevator> elevators) {
        // Sort requests by floor, and process in SCAN order
        requests.sort(Comparator.comparingInt(Request::getTargetFloor));
        processRequests(requests, elevators);
    }

    private void processRequests(List<Request> requests, List<Elevator> elevators) {
        for (Request request : requests) {
            Elevator selectedElevator = selectElevatorForRequest(request, elevators);
            selectedElevator.moveTo(request.getTargetFloor());
        }
    }

    private Elevator selectElevatorForRequest(Request request, List<Elevator> elevators) {
        // Simple heuristic: Choose the elevator closest to the requested floor
        return elevators.stream().min(Comparator.comparingInt(elevator -> Math.abs(elevator.getCurrentFloor() - request.getTargetFloor()))).get();
    }
}

class PriorityScheduler implements RequestSchedulingStrategy {
    @Override
    public void scheduleRequest(List<Request> requests, List<Elevator> elevators) {
        // Sort requests by priority (higher priority for lower floors)
        requests.sort(Comparator.comparingInt(Request::getTargetFloor));
        processRequests(requests, elevators);
    }

    private void processRequests(List<Request> requests, List<Elevator> elevators) {
        for (Request request : requests) {
            Elevator selectedElevator = selectElevatorForRequest(request, elevators);
            selectedElevator.moveTo(request.getTargetFloor());
        }
    }

    private Elevator selectElevatorForRequest(Request request, List<Elevator> elevators) {
        // Simple heuristic: Choose the closest elevator
        return elevators.stream().min(Comparator.comparingInt(elevator -> Math.abs(elevator.getCurrentFloor() - request.getTargetFloor()))).get();
    }
}

class ElevatorControlSystem {
    private List<Elevator> elevators;
    private List<Request> requestQueue;
    private RequestSchedulingStrategy schedulingStrategy;

    public ElevatorControlSystem(int numElevators, RequestSchedulingStrategy schedulingStrategy) {
        this.elevators = new ArrayList<>();
        for (int i = 0; i < numElevators; i++) {
            elevators.add(new Elevator(i + 1));
        }
        this.requestQueue = new ArrayList<>();
        this.schedulingStrategy = schedulingStrategy;
    }

    public void addRequest(Request request) {
        requestQueue.add(request);
    }

    public void processRequests() {
        schedulingStrategy.scheduleRequest(requestQueue, elevators);
    }
}
```

**4. Command Pattern for Request Processing**

The **Command Pattern** is used for encapsulating requests as command objects. This allows for flexibility and decouples the request generation from the execution of the request.

```java
interface Command {
    void execute();
}

class RequestCommand implements Command {
    private ElevatorControlSystem system;
    private Request request;

    public RequestCommand(ElevatorControlSystem system, Request request) {
        this.system = system;
        this.request = request;
    }

    @Override
    public void execute() {
        system.addRequest(request);
    }
}
```

***

#### **Main Class to Demonstrate the System**

```java
import java.util.*;

public class Main {
    public static void main(String[] args) {
        // Create a system with 3 elevators, using the FIFO scheduling strategy
        ElevatorControlSystem elevatorSystem = new ElevatorControlSystem(3, new FIFOScheduler());

        // Simulate requests (with time as part of FIFO)
        Request request1 = new Request(5, 1); // Request to go to 5th floor at time 1
        Request request2 = new Request(3, 2); // Request to go to 3rd floor at time 2
        Request request3 = new Request(7, 3); // Request to go to 7th floor at time 3

        // Add requests to the system
        Command command1 = new RequestCommand(elevatorSystem, request1);
        Command command2 = new RequestCommand(elevatorSystem, request2);
        Command command3 = new RequestCommand(elevatorSystem, request3);

        command1.execute();
        command2.execute();
        command3.execute();

        // Process requests with FIFO scheduling
        elevatorSystem.processRequests();
    }
}
```

***

#### **Explanation of Design Patterns Used**

1. **Strategy Pattern**:
   * The **RequestSchedulingStrategy** interface allows the system to dynamically select different request scheduling algorithms (FIFO, SCAN, Priority Weight). By using this pattern, we can easily switch between different strategies at runtime.
2. **Command Pattern**:
   * The **Command** interface, along with the **RequestCommand** class, encapsulates requests as objects, allowing for better flexibility and decoupling the request creation from request processing.
3. **Factory Pattern**:
   * While not explicitly shown here, we could apply the **Factory Pattern** to instantiate elevators or even scheduling strategies dynamically based on configurations or user inputs.
4. **Observer Pattern**:
   * This pattern can be used for notifying passengers when their requested elevator arrives. For example, each **Request** object could implement an observer that listens for the completion of the elevator’s movement.

***

#### **Conclusion**

The **Low-Level Design (LLD)** of the **Multi-Tier Elevator System** efficiently manages multiple elevators, schedules requests using different strategies, and handles command processing through the **Command Pattern**. By applying **Strategy Pattern**, we enable the system to easily switch between different request processing algorithms, such as **FIFO**, **SCAN**, and **Priority Weight**. This design is modular and extensible, making it easy to add new features like additional scheduling strategies or complex elevator behaviors.
