System Design
Object-Oriented Design
Elevator System

Design Example: Elevator System

Designing an Elevator System is a sophisticated OOD challenge that tests your ability to handle real-time requests, state management, and multi-object coordination.


Step 1: Requirements Gathering

Core Use Cases:

  • User presses a button on a floor to go up or down.
  • User inside the elevator selects a destination floor.
  • The system dispatches the most suitable elevator.
  • Elevators open/close doors and move between floors.

Clarifications:

  • How many elevators? (Multiple)
  • What is the dispatching goal? (Minimize wait time vs. minimize energy)
  • Support for emergency stops/overload? (Basic support)

Step 2: Identify Core Objects

  • Elevator: Represents the physical car with a current floor, direction, and state.
  • Button: Can be ExternalButton (on floors) or InternalButton (inside the car).
  • Floor: Represents a level in the building.
  • ElevatorController: Manages a single elevator's movement.
  • ElevatorSystem (Dispatcher): Orchestrates multiple elevators.

Step 3: Design Class Diagram


Step 4: Implementation in TypeScript

enum Direction { UP, DOWN, IDLE }
enum Status { MOVING, STOPPED, MAINTENANCE }
 
class Elevator {
  private currentFloor: number = 0;
  private direction: Direction = Direction.IDLE;
  private requests: Set<number> = new Set();
 
  public addRequest(floor: number) {
    this.requests.add(floor);
  }
 
  public move() {
    // Basic movement logic
    if (this.requests.size === 0) return;
    // Logic to update currentFloor and direction
  }
 
  public getCurrentFloor() { return this.currentFloor; }
  public getDirection() { return this.direction; }
}
 
interface DispatchStrategy {
  pickElevator(elevators: Elevator[], floor: number, dir: Direction): Elevator;
}
 
class ClosestIdleStrategy implements DispatchStrategy {
  pickElevator(elevators: Elevator[], floor: number, dir: Direction): Elevator {
    // Find the closest elevator that is IDLE or moving in the same direction
    return elevators.reduce((prev, curr) => {
      const prevDist = Math.abs(prev.getCurrentFloor() - floor);
      const currDist = Math.abs(curr.getCurrentFloor() - floor);
      return currDist < prevDist ? curr : prev;
    });
  }
}
 
class ElevatorSystem {
  private static instance: ElevatorSystem;
  private elevators: Elevator[] = [];
  private strategy: DispatchStrategy;
 
  private constructor() {
    this.strategy = new ClosestIdleStrategy();
    for (let i = 0; i < 3; i++) this.elevators.push(new Elevator());
  }
 
  public static getInstance() {
    if (!this.instance) this.instance = new ElevatorSystem();
    return this.instance;
  }
 
  public requestElevator(floor: number, direction: Direction) {
    const selected = this.strategy.pickElevator(this.elevators, floor, direction);
    selected.addRequest(floor);
  }
}

Deep Dive: Dispatching Algorithms

  1. FCFS (First-Come, First-Served): Simple but inefficient (starvation).
  2. SCAN (Elevator Algorithm): The elevator moves in one direction until it hits the end, then reverses.
  3. LOOK: Similar to SCAN but reverses as soon as there are no more requests in the current direction.

Wrap Up

An Elevator System is essentially a scheduling problem. By separating the DispatchStrategy from the ElevatorSystem, you make your design flexible and testable—which is exactly what interviewers look for.

[!IMPORTANT] In a high-traffic building, you might implement Destination Dispatching where users input their floor before entering the elevator to group passengers intelligently.