Model a multi-elevator system with a controller that schedules requests using the LOOK algorithm and tracks each elevator as a state machine.
Overview
An elevator system consists of one or more Elevator cars managed by an ElevatorController. Each elevator operates as a state machine with states Idle, MovingUp, MovingDown, and DoorsOpen. Requests originate either externally (hall button on a floor) or internally (panel inside the car). The LOOK scheduling algorithm minimises travel distance by servicing all requests in the current direction before reversing. Observer pattern notifies door-sensor listeners when doors open or close. This problem tests State, Strategy, and Observer pattern knowledge under a timed interview scenario.
Requirements Analysis
Functional: handle external hall requests (floor + direction) and internal cabin requests (destination floor), move elevator to correct floor, open/close doors, dispatch nearest idle elevator. Non-functional: extensible scheduling (swap LOOK for FCFS without changing Elevator), thread-safe request queue, real-time door-sensor events via Observer.
// Entities : ElevatorSystem, Elevator, ElevatorController, Request, Direction, ElevatorState
// Patterns : State (elevator lifecycle), Strategy (LOOK scheduler), Observer (door sensors)Core Classes & Relationships
Direction enum has UP, DOWN, IDLE. ElevatorState is an interface with handleRequest() and getStateName(). Concrete states: IdleState, MovingUpState, MovingDownState, DoorsOpenState. Request is a value object holding floor, direction, and type (INTERNAL/EXTERNAL). SchedulingStrategy interface is implemented by LookScheduler.
public enum Direction { UP, DOWN, IDLE }
public enum RequestType { INTERNAL, EXTERNAL }
public record Request(int floor, Direction direction, RequestType type) {}
public interface ElevatorState {
void handleRequest(Elevator elevator, Request request);
String getStateName();
}
public interface SchedulingStrategy {
Elevator selectElevator(List<Elevator> elevators, Request request);
}
public interface DoorSensorListener {
void onDoorsOpened(int floor);
void onDoorsClosed(int floor);
}Java Implementation
Elevator holds its current floor, direction, state, and a sorted destination set. transitionTo() swaps the state object. ElevatorController receives external requests and delegates to the SchedulingStrategy to pick an elevator. LookScheduler picks the nearest elevator moving in the same direction, or the nearest idle one.
public class Elevator {
private int currentFloor = 0;
private Direction direction = Direction.IDLE;
private ElevatorState state;
private final TreeSet<Integer> destinations = new TreeSet<>();
private final List<DoorSensorListener> listeners = new ArrayList<>();
public Elevator() { this.state = new IdleState(); }
public void addDestination(int floor) { destinations.add(floor); }
public void transitionTo(ElevatorState newState) { this.state = newState; }
public void addListener(DoorSensorListener l) { listeners.add(l); }
public void step() { // called by a scheduler tick
if (destinations.isEmpty()) { direction = Direction.IDLE; return; }
int next = direction == Direction.DOWN ? destinations.first() : destinations.last();
if (next > currentFloor) direction = Direction.UP;
else if (next < currentFloor) direction = Direction.DOWN;
currentFloor += (direction == Direction.UP ? 1 : -1);
if (currentFloor == next) {
destinations.remove(next);
listeners.forEach(l -> l.onDoorsOpened(currentFloor));
listeners.forEach(l -> l.onDoorsClosed(currentFloor));
}
}
public int getCurrentFloor() { return currentFloor; }
public Direction getDirection() { return direction; }
}
// ── Concrete states ───────────────────────────────────────────────
class IdleState implements ElevatorState {
@Override public void handleRequest(Elevator e, Request r) {
e.addDestination(r.floor());
e.transitionTo(r.floor() > e.getCurrentFloor() ? new MovingUpState() : new MovingDownState());
}
@Override public String getStateName() { return "IDLE"; }
}
class MovingUpState implements ElevatorState {
@Override public void handleRequest(Elevator e, Request r) {
if (r.floor() > e.getCurrentFloor()) e.addDestination(r.floor());
}
@Override public String getStateName() { return "MOVING_UP"; }
}
class MovingDownState implements ElevatorState {
@Override public void handleRequest(Elevator e, Request r) {
if (r.floor() < e.getCurrentFloor()) e.addDestination(r.floor());
}
@Override public String getStateName() { return "MOVING_DOWN"; }
}
// ── Controller ────────────────────────────────────────────────────
public class ElevatorController {
private final List<Elevator> elevators;
private final SchedulingStrategy scheduler;
public ElevatorController(List<Elevator> elevators, SchedulingStrategy scheduler) {
this.elevators = elevators;
this.scheduler = scheduler;
}
public void processRequest(Request request) {
Elevator chosen = scheduler.selectElevator(elevators, request);
chosen.addDestination(request.floor());
}
}Key Points to Remember
- 1State pattern encapsulates per-state behaviour: MovingUpState silently drops downward requests, IdleState accepts any.
- 2LOOK algorithm outperforms FCFS by batching same-direction requests, cutting average wait time significantly.
- 3Observer (DoorSensorListener) decouples door-open events from safety systems, display screens, and logging.
- 4Using a TreeSet for destinations gives O(log n) add and O(1) min/max access, perfect for LOOK direction checks.
Interview Questions
Sign in to ask AriaHow would you implement the LOOK disk-scheduling algorithm for elevator floor selection?
How does the State pattern help manage elevator lifecycle transitions compared to if-else chains?
How would you scale this design to handle 50 elevators across a skyscraper with real-time occupancy data?
Ask Aria about Design an Elevator System
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.