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);
}
}