DEV Community

Machine coding Master
Machine coding Master

Posted on • Originally published at javalld.com

Java LLD: Designing a Robust Vehicle Rental System

Java LLD: Designing a Robust Vehicle Rental System

Designing a Vehicle Rental System is a classic Low-Level Design (LLD) question frequently asked at companies like Uber, Grab, and Amazon. While the requirements seem simple on the surface, candidates often struggle to handle complex state transitions and dynamic pricing models cleanly under pressure.

The Mistake Most Candidates Make

  • Monolithic State Management: Using massive, nested if-else or switch-case blocks inside the Vehicle class to handle state transitions, leading to spaghetti code.
  • Hardcoded Pricing Logic: Embedding billing and pricing calculations directly inside the reservation flow, making it incredibly difficult to support dynamic or holiday rates.
  • Weak State Encapsulation: Allowing illegal state transitions (such as moving a vehicle directly from Reserved to UnderMaintenance) due to scattered validation logic.

The Right Approach

  • Core mental model: Model the vehicle's lifecycle as a self-contained state machine using the State Pattern, delegating transition rules directly to individual state objects.
  • Key entities/classes: Vehicle, VehicleState (interface), AvailableState, ReservedState, RentedState, UnderMaintenanceState, PricingStrategy, VehicleFactory.
  • Why it beats the naive approach: It strictly enforces the Open-Closed Principle, allowing you to add new states (like Damaged or InTransit) or billing rules without modifying existing classes.

I built javalld.com while prepping for senior roles — complete LLD problems with execution traces, not just theory.

The Key Insight (Code)

Here is how you cleanly reject illegal transitions at the state level using the State Pattern:

public interface VehicleState {
    void reserve(Vehicle vehicle);
    void rent(Vehicle vehicle);
}

public class RentedState implements VehicleState {
    @Override
    public void reserve(Vehicle vehicle) {
        throw new IllegalStateException("Cannot reserve a rented vehicle!");
    }

    @Override
    public void rent(Vehicle vehicle) {
        throw new IllegalStateException("Vehicle is already rented!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • State Pattern Enforces Constraints: Moving transition rules into dedicated state classes ensures illegal actions throw exceptions naturally, eliminating conditional clutter.
  • Strategy Pattern Decouples Billing: Separating pricing algorithms from the vehicle entity allows you to dynamically swap rates (e.g., hourly, weekly, or surge pricing).
  • Factory Pattern Centralizes Creation: Using a factory to instantiate different vehicle types (e.g., Cars, Bikes) keeps your client code decoupled from concrete implementations.

Full working implementation with execution trace available at https://javalld.com/problems/vehicle-rental

Top comments (0)