Bird
Raised Fist0

Car Rental System - Fleet, Booking, Pricing, Damage, Return

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
🏗️
Car Rental System - Fleet, Booking, Pricing, Damage, Return
Design a concurrent car rental system managing fleet, bookings, pricing, damages, and returns with extensible OOP design.
mediumBooking and Reservation SystemsFreq: medium
Prerequisites:Concurrency in Java (synchronized, volatile, Atomic classes)OOP Design principles (SOLID, design patterns)Java Collections and Exception Handling
⚙️
Functional Requirements
  • Manage fleet of cars with status (available, rented, maintenance)
  • Allow concurrent bookings ensuring no double-booking of same car
  • Calculate rental price based on car type, rental duration, and dynamic pricing rules
  • Track damages reported on cars and associate with bookings
  • Process car returns updating fleet status and billing final charges
  • Support cancellation and modification of bookings with concurrency safety
👤
Use Cases
  • Customer searches available cars by type and date range
  • Customer books a car for a specified period
  • Fleet Manager adds/removes cars from fleet
  • Pricing Manager updates pricing rules and calculates rental cost
  • Damage Inspector records damages on returned cars
  • Customer returns a car and system processes return and billing
🧑‍💻
Actors
  • Customer
  • Fleet Manager
  • Pricing Manager
  • Damage Inspector
  • System Scheduler
❓
Clarifying Questions to Ask
  • How many concurrent booking requests can the system expect? (Concurrency level)
  • Are there multiple return gates or a single return point? (Concurrency in returns)
  • Is pricing static or dynamic with time-based discounts or surge pricing?
  • What happens if a car is damaged during rental? Is damage inspection immediate or delayed?
  • Can bookings be modified or canceled after confirmation? What concurrency guarantees are needed?
  • Are cars uniquely identified and tracked individually or by model type only?
Out of Scope
✗ Payment gateway integration
✗ User authentication and authorization
✗ Mobile app UI design
✗ Long-term subscription plans
⚡
QPS Calculation
read qps500
write qps100
🖥️
Server Estimate
app servers5
db servers3
Estimates based on expected concurrent users and data volume to ensure scalability.
🔢
Enumerations
enum CarStatus
AVAILABLE | RENTED | MAINTENANCE | DAMAGED
Enum prevents typo bugs and enables exhaustive switch statements for car lifecycle management.
enum BookingStatus
PENDING | CONFIRMED | CANCELED | COMPLETED
Defines booking lifecycle states explicitly, preventing invalid transitions and enabling state checks.
enum DamageSeverity
MINOR | MODERATE | SEVERE
Categorizes damage severity for pricing adjustments and repair prioritization.
enum CarType
SEDAN | SUV | HATCHBACK | LUXURY
Defines car categories for pricing and availability filtering.
📦
Car
4 fields
private final String carIdprivate final CarType typeprivate volatile CarStatus statusprivate String licensePlate
Represents a single car in the fleet with unique identity, type, and current status.
public String getCarId()Returns unique identifier of the car.
public CarStatus getStatus()Returns current status of the car.
public synchronized void setStatus(CarStatus status)Atomically updates the car status to prevent race conditions.
📦
Booking
7 fields
private final String bookingIdprivate final String carIdprivate final String customerIdprivate final LocalDateTime startTimeprivate final LocalDateTime endTimeprivate volatile BookingStatus statusprivate double price
Manages booking details, lifecycle, and pricing for a car rental.
public synchronized boolean confirmBooking()Atomically confirms booking if still pending, preventing double confirmation.
public synchronized boolean cancelBooking()Atomically cancels booking if allowed, updating status safely.
public double calculatePrice(PricingStrategy strategy)Calculates rental price using provided pricing strategy.
📦
FleetManager
1 fields
private final Map<String, Car> cars = new ConcurrentHashMap<>()
Manages fleet inventory, adding/removing cars and querying availability.
public synchronized void addCar(Car car)Adds a new car to the fleet atomically.
public synchronized boolean removeCar(String carId)Removes a car from fleet if not rented, atomically.
public List<Car> getAvailableCars(CarType type, LocalDateTime start, LocalDateTime end)Returns list of cars available for given type and time range.
📦
PricingStrategy
0 fields
Abstract pricing calculation strategy for rental cost computation.
public abstract double calculatePrice(CarType type, long rentalDurationHours)Calculates price based on car type and rental duration.
📦
DamageReport
6 fields
private final String reportIdprivate final String carIdprivate final String bookingIdprivate final DamageSeverity severityprivate final String descriptionprivate final LocalDateTime reportedAt
Records damage details associated with a car and booking.
public DamageSeverity getSeverity()Returns severity of the damage.
public String getDescription()Returns textual description of damage.
📦
ReturnProcessor
2 fields
private final FleetManager fleetManagerprivate final DamageInspector damageInspector
Handles car return process including status update and damage recording.
public synchronized boolean processReturn(String bookingId, DamageReport damageReport)Atomically processes car return, updates fleet status, and records damage.
📦
DamageInspector
1 fields
private final List<DamageReport> damageReports = Collections.synchronizedList(new ArrayList<>())
Inspects and records damages reported on cars.
public synchronized void recordDamage(DamageReport report)Adds a damage report to the synchronized list.
public List<DamageReport> getDamageReportsForCar(String carId)Returns all damage reports for a specific car.
🗄️
Cars
PK: carId
carId STRING PRIMARY KEYtype STRINGstatus STRINGlicensePlate STRING
🗄️
Bookings
PK: bookingId
bookingId STRING PRIMARY KEYcarId STRINGcustomerId STRINGstartTime TIMESTAMPendTime TIMESTAMPstatus STRINGprice DOUBLE
🔌
GET /cars/available
Request
{
  "carType": "string",
  "startTime": "ISO8601 timestamp",
  "endTime": "ISO8601 timestamp"
}
Response
{
  "availableCars": "[Car]"
}
Returns list of available cars for given type and time range.
🔌
POST /bookings
Request
{
  "carId": "string",
  "customerId": "string",
  "startTime": "ISO8601 timestamp",
  "endTime": "ISO8601 timestamp"
}
Response
{
  "bookingId": "string",
  "status": "string"
}
Creates a new booking if car is available.
🔌
POST /returns
Request
{
  "bookingId": "string",
  "damageReport": "DamageReport object (optional)"
}
Response
{
  "success": "boolean",
  "finalPrice": "double"
}
Processes car return, updates status, and records damages.

Practice

(1/5)
1. In the hotel system, should Vehicle be designed as an abstract class or an interface, considering that different vehicle types have state like license plate and behavior like parking? Why?
easy
A. Interface, because it allows multiple inheritance and all vehicles share behavior only.
B. Abstract class, because vehicles share common state and behavior that can be reused.
C. Interface, because state should be stored externally to keep Vehicle stateless.
D. Abstract class, because interfaces cannot define any methods with implementation.

Solution

  1. Step 1: Analyze Vehicle's state and behavior

    Vehicle has common state (license plate) and behavior (park, unpark) shared by all types.
  2. Step 2: Abstract class vs interface for state and behavior

    Abstract classes can hold state and provide default behavior; interfaces cannot hold instance state (Java 8+ default methods don't hold state). Thus, abstract class fits better.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Shared state + behavior -> abstract class [check]
Hint: Stateful base class -> abstract class, not interface [check]
Common Mistakes:
2. In designing the Airline Reservation System, should the Seat entity be modeled as an abstract class or an interface, and why?
easy
A. Abstract class, because seats share common state like seat number and class, and behavior like availability checks.
B. Interface, because it allows multiple inheritance and flexible seat type combinations.
C. Interface, because seats only define behavior without any shared state or implementation.
D. Abstract class, because interfaces cannot enforce method signatures for seat operations.

Solution

  1. Step 1: Analyze seat characteristics

    Seats have shared state (seat number, class) and common behavior (availability, booking), which suggests code reuse.
  2. Step 2: Abstract class vs interface

    Abstract class allows shared state and default behavior implementation, while interface cannot hold state and only defines method signatures.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Shared state + behavior -> abstract class [check]
Hint: Shared state needs abstract class, interfaces lack fields [check]
Common Mistakes:
3. A class SecureImageProxy controls access to RealImage by checking user permissions before loading the image data lazily. Which design pattern is this an example of, and why is it the correct choice here?
easy
A. Proxy pattern, because it controls access and delays expensive object creation until needed.
B. Decorator pattern, because it adds responsibilities dynamically without changing the original object.
C. Adapter pattern, because it converts the interface of RealImage to a different one.
D. Facade pattern, because it provides a simplified interface to a complex subsystem.

Solution

  1. Step 1: Identify the role of SecureImageProxy

    This class controls access to RealImage and delays loading until necessary, matching Proxy's intent.
  2. Step 2: Eliminate other patterns

    Decorator adds behavior without access control; Adapter changes interface; Facade simplifies interface but doesn't control access or lazy load.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Proxy controls access and lazy loads expensive objects [check]
Hint: Proxy controls access and lazy loads objects [check]
Common Mistakes:
4. Adding a WeekendFeeStrategy to the parking lot pricing requires which minimum change to comply with SOLID principles?
medium
A. Add a boolean flag isWeekend to ParkingLot and handle fees internally.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without modifying existing classes.
C. Extend ParkingLot with a subclass WeekendParkingLot that overrides fee calculation.
D. Modify the existing FeeStrategy class to add weekend logic with an if-statement.

Solution

  1. Step 1: Identify the SOLID principle involved

    The Open/Closed Principle (OCP) requires that classes be open for extension but closed for modification.
  2. Step 2: Evaluate options against OCP

    Add a boolean flag isWeekend to ParkingLot and handle fees internally. adds weekend logic inside ParkingLot, modifying existing code and violating OCP. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without modifying existing classes. creates a new strategy class and injects it, adhering to OCP. Modify the existing FeeStrategy class to add weekend logic with an if-statement. modifies FeeStrategy directly, violating OCP. Extend ParkingLot with a subclass WeekendParkingLot that overrides fee calculation. subclasses ParkingLot, which can cause class explosion and violates single responsibility.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Modifying ParkingLot internals violates OCP -> not minimal change [check]
Hint: OCP: extend with new class, don't modify existing code [check]
Common Mistakes:
5. To add support for ElectricCar and ChargingSpot in the Chess game parking lot design, what is the minimum change that respects extensibility without modifying existing classes?
hard
A. Create new ElectricCar and ChargingSpot classes and modify ParkingLot to handle them explicitly.
B. Modify VehicleType and SpotType enums to include electric types and add compatibility logic inside existing classes.
C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
D. Add a boolean isElectric flag to Vehicle and Spot classes and handle charging logic inside existing methods.

Solution

  1. Step 1: Identify extensibility requirements

    New vehicle and spot types must be added without modifying existing classes to respect OCP.
  2. Step 2: Evaluate Java enum and class extension approach

    Adding new enum constants and creating new subclasses externally allows extension without modifying existing code. Updating compatibility map externally avoids class explosion.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Extends enums and classes externally, no existing class changes [check]
Hint: Extend enums + subclasses externally, no existing class edits [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard