Elevator System
An elevator's behavior genuinely depends on which of a handful of discrete states it is in - idle, moving, doors open - and the request that just arrived means something different in each one. That makes it a good showcase for the State pattern from the catalog: not because every machine-coding problem needs a pattern, but because this one's requirements already have pattern-shaped seams.
Requirements
Functional
- A hall button (floor + direction) or a cabin button (destination floor) can request the elevator at any time.
- The elevator serves requests in an order that makes sense - it should not reverse direction while requests remain ahead of it in the direction it's already moving.
- Multiple elevators exist; a hall request should go to whichever one can reach that floor soonest, not always elevator #1.
Non-functional
- Adding a new state (say, a maintenance/out-of-service mode) should not require touching the logic of the other states.
- Dispatch (which elevator gets a request) should be swappable independent of how a single elevator processes its own request queue.
Design
Two decisions carry this design. First, Elevator never has an if (state == MOVING)
anywhere in it - it holds a ElevatorState object and forwards every event to it. Second,
picking which elevator answers a hall call is not the elevator's job at all; it belongs to
ElevatorController, so a smarter dispatch algorithm later never touches Elevator.
- 1A passenger on floor 5 wants to go up. The button only knows the controller.
- 2The controller picks the elevator with the smallest floor distance - this is the only class allowed to compare elevators to each other.
- 3The chosen elevator is told to serve floor 5; it does not know it was chosen over others.
- 4Elevator forwards the event to whatever state it currently holds - today that is IdleState.
- 5IdleState decides the elevator should move and swaps in a MovingState.
- 6Each tick, the elevator asks its current state what to do next - move one floor, or stop.
- 7On reaching floor 5, MovingState swaps in DoorOpenState; doors open without Elevator ever checking a floor number itself.
Class diagram
Code
Design decisions
- State pattern, not a status flag. An
ElevatorStatusenum withif/switchblocks scattered acrossmove(),requestFloor(), andopenDoors()is where elevator bugs actually live in practice - one branch gets updated for a new state, another is forgotten. Giving each state its own class means the compiler (or at least a code reviewer) can see every place a new state has to plug in. - Dispatch lives in the controller, not the elevator.
Elevatoronly knows how to react to its own requests; it has no idea other elevators exist.ElevatorControlleris the only class that compares elevators to each other, so "nearest elevator" can become "nearest elevator going the same direction" later withoutElevatorchanging at all. - Requests are a sorted structure, not a plain list. Serving requests in floor order (rather than arrival order) is what keeps the elevator from bouncing - the sweep direction only reverses once there is nothing left ahead of it.
- What's missing for a real system: starvation (a request in the opposite direction can
wait through several sweeps under high load - a real answer ages requests or caps sweep
length), and concurrent requests arriving while
move()is mid-step need the request queue to be thread-safe, which this single-threaded walkthrough sidesteps.