problemhardood

Object-Oriented Design for a Car Rental System

Problem

Design an object-oriented system to manage a multi-location car rental business: vehicle catalog (cars, trucks, vans, SUVs, motorcycles), reservations with optional equipment/services/insurance, pick-up and return workflows (including late fees), notifications for upcoming and overdue returns, and vehicle event logging across branches.

Solution

1. Requirements Analysis

Functional Requirements:

  • Support multiple vehicle types (car, truck, SUV, van, motorcycle) each with unique barcode and parking stall/location identifiers.
  • Allow search and reservation of available vehicles; enable cancellation.
  • Track which member rented which vehicle and list rentals per member.
  • Record vehicle events (log entries: accident, fueling, cleaning, damage, service, etc.).
  • Process pick-up (checkout) and return flows; compute and collect late fees after due date.
  • Add optional rental insurance, equipment (navigation, child seat, ski rack), and services (roadside assistance, additional driver, wifi) to reservations.
  • Send notifications for approaching pick-up times, upcoming due dates, and overdue returns.
  • Barcode scanning capability for quick vehicle identification.
  • Maintain multiple rental locations each with its inventory.

Non-Functional (implicit):

  • Extensibility for new vehicle types/equipment/services.
  • Auditability via comprehensive vehicle log and reservation records.
  • Reliability of notification dispatch around critical time thresholds.

Car Rental System

2. Use Case Diagram

Actors: Receptionist, Member, System, Worker. Key Use Cases: Add/Edit Vehicle, Search Catalog, Register/Cancel Membership, Reserve Vehicle, Check-out Vehicle, Return Vehicle, Add Equipment/Insurance/Service, Update Vehicle Log.

graph TD
    subgraph CRS[Car Rental System]
        UC_Add(Add/Edit Vehicle)
        UC_Search(Search Catalog)
        UC_Register(Register/Cancel Membership)
        UC_Reserve(Reserve Vehicle)
        UC_Checkout(Check-out Vehicle)
        UC_Return(Return Vehicle)
        UC_AddEquip(Add Equipment/Service/Insurance)
        UC_UpdateLog(Update Vehicle Log)
    end
    Receptionist --> UC_Add
    Receptionist --> UC_Reserve
    Member --> UC_Search
    Member --> UC_Reserve
    Member --> UC_Checkout
    Member --> UC_Return
    Member --> UC_AddEquip
    Worker --> UC_UpdateLog
    System --> UC_Reserve
    System --> UC_Return

Car Rental System Use Case Diagram

3. Class Diagram

Core Classes:

  • CarRentalSystem: Aggregates locations and high-level operations.
  • CarRentalLocation: Represents a physical branch with address and inventory.
  • Vehicle (Car, Van, Truck, ...): Base vehicle attributes (barcode, license, capacity, status, model/make/year/mileage) and reservation lifecycle operations.
  • VehicleReservation: Manages reservation details (dates, status, drivers, add-ons, billing).
  • VehicleLog: Records events for vehicles.
  • Account (Member, Receptionist): User identities and roles; AdditionalDriver for service add-on.
  • Equipment / Service / RentalInsurance / Bill: Reservation add-on entities and billing.
  • Search / VehicleInventory: Provides search by type/model.
classDiagram
    class CarRentalSystem { +name: String +addNewLocation(location) }
    class CarRentalLocation { +name: String +address: Address }
    class Vehicle { +licenseNumber: String +barcode: String +status: VehicleStatus +reserveVehicle() +returnVehicle() }
    class Car { }
    class Van { }
    class Truck { }
    Vehicle <|-- Car
    Vehicle <|-- Van
    Vehicle <|-- Truck
    class VehicleReservation { +reservationNumber: String +status: ReservationStatus +fetchDetails(num) }
    class VehicleLog { +id: String +update() }
    class Account { +id: String +resetPassword() }
    class Member { +getReservations() }
    class Receptionist { +searchMember(name) }
    Account <|-- Member
    Account <|-- Receptionist
    class AdditionalDriver { +driverId: String }
    class Equipment { +name: String }
    class Service { +name: String }
    class RentalInsurance { +name: String }
    class Bill { }
    class VehicleInventory { +searchByType(t) +searchByModel(m) }
    CarRentalSystem "1" -- "*" CarRentalLocation : has
    CarRentalLocation "1" -- "*" Vehicle : inventory
    Vehicle "1" -- "*" VehicleLog : logs
    Member "1" -- "*" VehicleReservation : reservations
    VehicleReservation "1" -- "*" Vehicle : reserves
    VehicleReservation "1" -- "*" Equipment : includes
    VehicleReservation "1" -- "*" Service : includes
    VehicleReservation "1" -- "*" RentalInsurance : includes
    VehicleReservation "1" -- "*" AdditionalDriver : drivers

Car Rental System Class Diagram Car Rental System UML

4. Activity Diagrams

Activity: Pick Up Vehicle

graph TD
    P1[Member arrives] --> P2[Provide reservation number]
    P2 --> P3{Reservation valid & vehicle available?}
    P3 -- No --> P4[Resolve issue]
    P3 -- Yes --> P5[Update status to LOANED]
    P5 --> P6[Record pickup time]
    P6 --> P7[Optionally add equipment/services]

Car Rental System Pick Up Activity Diagram

Activity: Return Vehicle

graph TD
    R1[Member returns vehicle] --> R2[Inspect vehicle]
    R2 --> R3[Calculate mileage & fuel]
    R3 --> R4{Late?}
    R4 -- Yes --> R5[Apply late fee]
    R4 -- No --> R6[No late fee]
    R5 --> R7[Update logs]
    R6 --> R7[Update logs]
    R7 --> R8[Set status AVAILABLE]

Car Rental System Return Activity Diagram

5. High-Level Code Implementation

Java

enum VehicleStatus { AVAILABLE, RESERVED, LOANED, LOST, BEING_SERVICED, OTHER }
enum ReservationStatus { ACTIVE, PENDING, CONFIRMED, COMPLETED, CANCELLED, NONE }
enum AccountStatus { ACTIVE, CLOSED, CANCELED, BLACKLISTED, BLOCKED }

class Address { String street, city, state, zip, country; }

abstract class Account { String id; String password; AccountStatus status; void resetPassword(){} }
class Member extends Account { int totalVehiclesReserved; void getReservations(){} }
class Receptionist extends Account { String dateJoined; void searchMember(String name){} }
class AdditionalDriver { String driverId; }

abstract class Vehicle { String licenseNumber; String barcode; VehicleStatus status; String model; String make; int year; int mileage; void reserveVehicle(){} void returnVehicle(){} }
class Car extends Vehicle { }
class Van extends Vehicle { }
class Truck extends Vehicle { }

class VehicleLog { String id; String type; String description; String creationDate; void update(){} }

class VehicleReservation { String reservationNumber; ReservationStatus status; String dueDate; String returnDate; String pickupLocation; String returnLocation; void fetchReservationDetails(String num){} }

class Equipment { String name; }
class Service { String name; }
class RentalInsurance { String name; }
class Bill { }

class VehicleInventory { java.util.Map<String, java.util.List<Vehicle>> byType; java.util.Map<String, java.util.List<Vehicle>> byModel; java.util.List<Vehicle> searchByType(String t){ return byType.get(t); } java.util.List<Vehicle> searchByModel(String m){ return byModel.get(m); } }

class CarRentalLocation { String name; Address address; }
class CarRentalSystem { String name; java.util.List<CarRentalLocation> locations; void addNewLocation(CarRentalLocation loc){} }

Python

from enum import Enum
from typing import List, Dict

class VehicleStatus(Enum):
    AVAILABLE = 1; RESERVED = 2; LOANED = 3; LOST = 4; BEING_SERVICED = 5; OTHER = 6
class ReservationStatus(Enum):
    ACTIVE = 1; PENDING = 2; CONFIRMED = 3; COMPLETED = 4; CANCELLED = 5; NONE = 6
class AccountStatus(Enum):
    ACTIVE = 1; CLOSED = 2; CANCELED = 3; BLACKLISTED = 4; BLOCKED = 5

class Address:
    def __init__(self, street: str, city: str, state: str, zip_code: str, country: str) -> None:
        self.street = street; self.city = city; self.state = state; self.zip_code = zip_code; self.country = country

class Account:
    def __init__(self, id: str, password: str, status: AccountStatus) -> None:
        self.id = id; self.password = password; self.status = status
    def reset_password(self) -> None: pass

class Member(Account):
    def __init__(self, id: str, password: str) -> None:
        super().__init__(id, password, AccountStatus.ACTIVE); self.total_vehicles_reserved = 0
    def get_reservations(self) -> None: pass

class Receptionist(Account):
    def __init__(self, id: str, password: str, date_joined: str) -> None:
        super().__init__(id, password, AccountStatus.ACTIVE); self.date_joined = date_joined
    def search_member(self, name: str) -> None: pass

class AdditionalDriver:
    def __init__(self, driver_id: str) -> None:
        self.driver_id = driver_id

class Vehicle:
    def __init__(self, license_number: str, barcode: str, status: VehicleStatus, model: str, make: str, year: int, mileage: int) -> None:
        self.license_number = license_number; self.barcode = barcode; self.status = status; self.model = model; self.make = make; self.year = year; self.mileage = mileage
    def reserve_vehicle(self) -> None: pass
    def return_vehicle(self) -> None: pass

class Car(Vehicle):
    pass
class Van(Vehicle):
    pass
class Truck(Vehicle):
    pass

class VehicleLog:
    def __init__(self, id: str, log_type: str, description: str, creation_date: str) -> None:
        self.id = id; self.log_type = log_type; self.description = description; self.creation_date = creation_date
    def update(self) -> None: pass

class VehicleReservation:
    def __init__(self, reservation_number: str, status: ReservationStatus) -> None:
        self.reservation_number = reservation_number; self.status = status; self.due_date = ""; self.return_date = ""; self.pickup_location_name = ""; self.return_location_name = ""
        self.additional_drivers: List[AdditionalDriver] = []
        self.equipments: List[str] = []
        self.services: List[str] = []
        self.insurances: List[str] = []
    def fetch_reservation_details(self, reservation_number: str) -> None: pass

class Equipment:
    def __init__(self, name: str) -> None: self.name = name
class Service:
    def __init__(self, name: str) -> None: self.name = name
class RentalInsurance:
    def __init__(self, name: str) -> None: self.name = name
class Bill:
    pass

class VehicleInventory:
    def __init__(self) -> None:
        self.by_type: Dict[str, List[Vehicle]] = {}
        self.by_model: Dict[str, List[Vehicle]] = {}
    def search_by_type(self, t: str) -> List[Vehicle]: return self.by_type.get(t, [])
    def search_by_model(self, m: str) -> List[Vehicle]: return self.by_model.get(m, [])

class CarRentalLocation:
    def __init__(self, name: str, address: Address) -> None:
        self.name = name; self.address = address

class CarRentalSystem:
    def __init__(self, name: str) -> None:
        self.name = name; self.locations: List[CarRentalLocation] = []
    def add_new_location(self, location: CarRentalLocation) -> None:
        self.locations.append(location)

Car Rental System Pick Up Activity Diagram Car Rental System Return Activity Diagram

Source https://github.com/tssovi/grokking-the-object-oriented-design-interview

System Requirements

We will focus on the following set of requirements while designing our Car Rental System:

  1. The system will support the renting of different automobiles like cars, trucks, SUVs, vans, and motorcycles.
  2. Each vehicle should be added with a unique barcode and other details, including a parking stall number which helps to locate the vehicle.
  3. The system should be able to retrieve information like which member took a particular vehicle or what vehicles have been rented out by a specific member.
  4. The system should collect a late-fee for vehicles returned after the due date.
  5. Members should be able to search the vehicle inventory and reserve any available vehicle.
  6. The system should be able to send notifications whenever the reservation is approaching the pick-up date, as well as when the vehicle is nearing the due date or has not been returned within the due date.
  7. The system will be able to read barcodes from vehicles.
  8. Members should be able to cancel their reservations.
  9. The system should maintain a vehicle log to track all events related to the vehicles.
  10. Members can add rental insurance to their reservation.
  11. Members can rent additional equipment, like navigation, child seat, ski rack, etc.
  12. Members can add additional services to their reservation, such as roadside assistance, additional driver, wifi, etc.

Use Case Diagram

We have four main Actors in our system:

  • Receptionist: Mainly responsible for adding and modifying vehicles and workers. Receptionists can also reserve vehicles.
  • Member: All members can search the catalog, as well as reserve, pick-up, and return a vehicle.
  • System: Mainly responsible for sending notifications about overdue vehicles, canceled reservation, etc.
  • Worker: Mainly responsible for taking care of a returned vehicle and updating the vehicle log.

Here are the top use cases of the Car Rental System:

  • Add/Remove/Edit vehicle: To add, remove or modify a vehicle.
  • Search catalog: To search for vehicles by type and availability.
  • Register new account/Cancel membership: To add a new member or cancel an existing membership.
  • Reserve vehicle: To reserve a vehicle.
  • Check-out vehicle: To rent a vehicle.
  • Return a vehicle: To return a vehicle which was checked-out to a member.
  • Add equipment: To add an equipment to a reservation like navigation, child seat, etc.
  • Update car log: To add or update a car log entry, such as refueling, cleaning, damage, etc.

Here is the use case diagram of our Car Rental System:

Car Rental System Use Case Diagram

Use Case Diagram for Car Rental System

Class Diagram

Here are the main classes of our Car Rental System:

  • CarRentalSystem: The main part of the organization for which this software has been designed.
  • CarRentalLocation: The car rental system will have multiple locations, each location will have attributes like ‘Name’ to distinguish it from any other locations and ‘Address’ which defines the address of the rental location.
  • Vehicle: The basic building block of the system. Every vehicle will have a barcode, license plate number, passenger capacity, model, make, mileage, etc. Vehicles can be of multiple types, like car, truck, SUV, etc.
  • Account: Mainly, we will have two types of accounts in the system, one will be a general member and the other will be a receptionist. Another account can be of the worker taking care of the returned vehicle.
  • VehicleReservation: This class will be responsible for managing reservations for a vehicle.
  • Notification: Will take care of sending notifications to members.
  • VehicleLog: To keep track of all the events related to a vehicle.
  • RentalInsurance: Stores details about the various rental insurances that members can add to their reservation.
  • Equipment: Stores details about the various types of equipment that members can add to their reservation.
  • Service: Stores details about the various types of service that members can add to their reservation, such as additional drivers, roadside assistance, etc.
  • Bill: Contains different bill-items for every charge for the reservation.

Car Rental System Class Diagram

Class Diagram for Car Rental System

Car Rental System UML

UML for Car Rental System

Activity Diagrams

Pick up a vehicle: Any member can perform this activity. Here are the steps to pick up a vehicle:

Car Rental System Pick Up Activity Diagram

Activity Diagram for Car Rental System Pick Up

Return a vehicle: Any worker can perform this activity. While returning a vehicle, the system must collect a late fee from the member if the return date is after the due date. Here are the steps for returning a vehicle:

Car Rental System Return Activity Diagram

Activity Diagram for Car Rental System Return

Code

Here is the high-level definition for the classes described above.

Enums, data types and constants: Here are the required enums, data types, and constants:

from enum import Enum


class BillItemType(Enum):
    BASE_CHARGE, ADDITIONAL_SERVICE, FINE, OTHER = 1, 2, 3, 4


class VehicleLogType(Enum):
    ACCIDENT, FUELING, CLEANING_SERVICE, OIL_CHANGE, REPAIR, OTHER = 1, 2, 3, 4, 5, 6


class VanType(Enum):
    PASSENGER, CARGO = 1, 2


class CarType(Enum):
    ECONOMY, COMPACT, INTERMEDIATE, STANDARD, FULL_SIZE, PREMIUM, LUXURY = 1, 2, 3, 4, 5, 6, 7


class VehicleStatus(Enum):
    AVAILABLE, RESERVED, LOANED, LOST, BEING_SERVICED, OTHER = 1, 2, 3, 4, 5, 6


class ReservationStatus(Enum):
    ACTIVE, PENDING, CONFIRMED, COMPLETED, CANCELLED, NONE = 1, 2, 3, 4, 5, 6


class AccountStatus(Enum):
    ACTIVE, CLOSED, CANCELED, BLACKLISTED, BLOCKED = 1, 2, 3, 4, 5


class PaymentStatus(Enum):
    UNPAID, PENDING, COMPLETED, FILLED, DECLINED, CANCELLED, ABANDONED, SETTLING, SETTLED, REFUNDED = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10


class Address:
    def __init__(self, street, city, state, zip_code, country):
        self.__street_address = street
        self.__city = city
        self.__state = state
        self.__zip_code = zip_code
        self.__country = country


class Person():
    def __init__(self, name, address, email, phone):
        self.__name = name
        self.__address = address
        self.__email = email
        self.__phone = phone

Account, Member, Receptionist, and Additional Driver: These classes represent different people that interact with our system:

from abc import ABC
from .constants import AccountStatus


# For simplicity, we are not defining getter and setter functions. The reader can
# assume that all class attributes are private and accessed through their respective
# public getter methods and modified only through their public methods function.


class Account(ABC):
    def __init__(self, id, password, person, status=AccountStatus.NONE):
        self.__id = id
        self.__password = password
        self.__status = AccountStatus.NONE
        self.__person = person

    def reset_password(self):
        None


class Member(Account):
    def __init__(self):
        self.__total_vehicles_reserved = 0

    def get_reservations(self):
        None


class Receptionist(Account):
    def __init__(self, date_joined):
        self.__date_joined = date_joined

    def search_member(self, name):
        None


class AdditionalDriver:
    def __init__(self, id, person):
        self.__driver_id = id
        self.__person = person

CarRentalSystem and CarRentalLocation: These classes represent the top level classes:

class CarRentalLocation:
    def __init__(self, name, address):
        self.__name = name
        self.__location = address

    def get_location(self):
        return self.__location


class CarRentalSystem:
    def __init__(self, name):
        self.__name = name
        self.__locations = []

    def add_new_location(self, location):
        None

Vehicle, VehicleLog, and VehicleReservation: To encapsulate a vehicle, log, and reservation. The VehicleReservation class will be responsible for processing the reservation and return of a vehicle:

from abc import ABC
from datetime import datetime
from .constants import ReservationStatus


class Vehicle(ABC):
    def __init__(self, license_num, stock_num, capacity, barcode, has_sunroof, status, model, make, manufacturing_year,
                 mileage):
        self.__license_number = license_num
        self.__stock_number = stock_num
        self.__passenger_capacity = capacity
        self.__barcode = barcode
        self.__has_sunroof = has_sunroof
        self.__status = status
        self.__model = model
        self.__make = make
        self.__manufacturing_year = manufacturing_year
        self.__mileage = mileage
        self.__log = []

    def reserve_vehicle(self):
        None

    def return_vehicle(self):
        None


class Car(Vehicle):
    def __init__(self, license_num, stock_num, capacity, barcode, has_sunroof, status, model, make, manufacturing_year,
                 mileage, type):
        super().__init__(license_num, stock_num, capacity, barcode,
                         has_sunroof, status, model, make, manufacturing_year, mileage)
        self.__type = type


class Van(Vehicle):
    def __init__(self, license_num, stock_num, capacity, barcode, has_sunroof, status, model, make, manufacturing_year,
                 mileage, type):
        super().__init__(license_num, stock_num, capacity, barcode,
                         has_sunroof, status, model, make, manufacturing_year, mileage)
        self.__type = type


class Truck(Vehicle):
    def __init__(self, license_num, stock_num, capacity, barcode, has_sunroof, status, model, make, manufacturing_year,
                 mileage, type):
        super().__init__(license_num, stock_num, capacity, barcode,
                         has_sunroof, status, model, make, manufacturing_year, mileage)
        self.__type = type


# We can have similar definition for other vehicle types

# ...

class VehicleLog:
    def __init__(self, id, type, description, creation_date):
        self.__id = id
        self.__type = type
        self.__description = description
        self.__creation_date = creation_date

    def update(self):
        None

    def search_by_log_type(self, type):
        None


class VehicleReservation:
    def __init__(self, reservation_number):
        self.__reservation_number = reservation_number
        self.__creation_date = datetime.date.today()
        self.__status = ReservationStatus.ACTIVE
        self.__due_date = datetime.date.today()
        self.__return_date = datetime.date.today()
        self.__pickup_location_name = ""
        self.__return_location_name = ""

        self.__customer_id = 0
        self.__vehicle = None
        self.__bill = None
        self.__additional_drivers = []
        self.__notifications = []
        self.__insurances = []
        self.__equipments = []
        self.__services = []

    def fetch_reservation_details(self, reservation_number):
        None

    def get_additional_drivers(self):
        return self.__additional_drivers

VehicleInventory and Search: VehicleInventory will implement an interface ‘Search’ to facilitate the searching of vehicles:

from abc import ABC


class Search(ABC):
    def search_by_type(self, type):
        None

    def search_by_model(self, model):
        None


class VehicleInventory(Search):
    def __init__(self):
        self.__vehicle_types = {}
        self.__vehicle_models = {}

    def search_by_type(self, query):
        # return all vehicles of the given type.
        return self.__vehicle_types.get(query)

    def search_by_model(self, query):
        # return all vehicles of the given model.
        return self.__vehicle_models.get(query)

Source https://github.com/tssovi/grokking-the-object-oriented-design-interview

Comments