Back to LLD explorer
System Design / State• Patterns: State, Strategy (Dispatching)

Elevator System

Hard

Problem Summary

Design a multi-car Elevator Control System managing hall calls, car panel requests, door lifecycle states, and the LOOK/SCAN elevator scheduling dispatch algorithm.

Functional Scope

  • Manage multiple elevator cars operating concurrently across N floors.
  • Internal floor destination buttons and external hall call (Up/Down) buttons.
  • Car states: Idle, MovingUp, MovingDown, DoorOpening, Maintenance.
  • Optimal elevator car selection via LOOK / SCAN dispatch heuristic.
  • Emergency stop button and weight overload safety sensor.

Entity-Relationship (ER) Schema

ElevatorController [1] --> [*] ElevatorCar
ElevatorCar [1] --> [1] CarState
ElevatorController [1] --> [1] DispatchStrategy
ElevatorCar [1] --> [*] FloorRequest

Design Approach

Use the LOOK elevator algorithm with sorted trees (TreeSet) for up and down stops to minimize elevator turnaround time and eliminate passenger starvation.

Core Classes & Models

ElevatorController (Orchestrator assigning hall calls to candidate cars)ElevatorCar (Maintains current floor, direction, and request queues)CarState (IdleState, MovingUpState, MovingDownState)DispatchStrategy (LOOKDispatchStrategy, NearestCarStrategy)FloorRequest (Floor, direction, internal vs external)
Code Blueprint
98 lines
/**
 * Low-Level Design: Multi-Car Elevator System
 * Design Patterns Applied:
 *  - State Pattern: Elevator car motion states (IdleState, MovingUpState, MovingDownState)
 *  - Strategy Pattern: Request dispatching algorithm (LOOK / SCAN vs Shortest Seek Time First)
 */

import java.util.*;

enum Direction { UP, DOWN, IDLE }

// --- [DESIGN PATTERN: State] Motion state interface ---
interface ElevatorState {
    void handleRequest(ElevatorCar car, int destinationFloor);
}

class IdleState implements ElevatorState {
    @Override
    public void handleRequest(ElevatorCar car, int floor) {
        if (floor > car.getCurrentFloor()) {
            car.setDirection(Direction.UP);
            car.setState(new MovingUpState());
            System.out.println("🔼 Elevator [" + car.getId() + "] starting UP to floor " + floor);
        } else if (floor < car.getCurrentFloor()) {
            car.setDirection(Direction.DOWN);
            car.setState(new MovingDownState());
            System.out.println("🔽 Elevator [" + car.getId() + "] starting DOWN to floor " + floor);
        }
    }
}

class MovingUpState implements ElevatorState {
    @Override
    public void handleRequest(ElevatorCar car, int floor) {
        car.addStop(floor);
    }
}

class MovingDownState implements ElevatorState {
    @Override
    public void handleRequest(ElevatorCar car, int floor) {
        car.addStop(floor);
    }
}

class ElevatorCar {
    private final int id;
    private int currentFloor = 1;
    private Direction direction = Direction.IDLE;
    private ElevatorState state = new IdleState();
    private final TreeSet<Integer> stops = new TreeSet<>();

    public ElevatorCar(int id) { this.id = id; }
    public int getId() { return id; }
    public int getCurrentFloor() { return currentFloor; }
    public Direction getDirection() { return direction; }
    public void setDirection(Direction d) { this.direction = d; }
    public void setState(ElevatorState s) { this.state = s; }
    public void addStop(int f) { stops.add(f); }

    public void requestFloor(int floor) {
        stops.add(floor);
        state.handleRequest(this, floor);
    }
}

// --- [DESIGN PATTERN: Strategy] Elevator selection algorithm ---
interface DispatchStrategy {
    ElevatorCar pickBestCar(List<ElevatorCar> cars, int sourceFloor, Direction dir);
}

class NearestCarStrategy implements DispatchStrategy {
    @Override
    public ElevatorCar pickBestCar(List<ElevatorCar> cars, int floor, Direction dir) {
        ElevatorCar best = null;
        int minDistance = Integer.MAX_VALUE;
        for (ElevatorCar c : cars) {
            int dist = Math.abs(c.getCurrentFloor() - floor);
            if (dist < minDistance) {
                minDistance = dist;
                best = c;
            }
        }
        return best;
    }
}

public class Main {
    public static void main(String[] args) {
        List<ElevatorCar> bank = List.of(new ElevatorCar(1), new ElevatorCar(2));
        DispatchStrategy dispatcher = new NearestCarStrategy();

        System.out.println("--- Elevator Dispatch Simulation ---");
        ElevatorCar assigned = dispatcher.pickBestCar(bank, 7, Direction.UP);
        System.out.println("Assigned Car #" + assigned.getId() + " to Hall Call at Floor 7");
        assigned.requestFloor(7);
    }
}