Code · LLD machine coding · Personal project

Car Rental System

Search cars by make, model and dates; reserve, cancel, and pay. Overlapping reservations are rejected, and reservations are thread-safe.

9 classes 219 lines SingletonStrategyConcurrentHashMapsynchronizedEnums
CarRentalSystem.java 74 lines
package carrentalsystem;

import carrentalsystem.entities.Car;
import carrentalsystem.entities.Customer;
import carrentalsystem.entities.Reservation;
import carrentalsystem.payment.CreditCardPaymentProcessor;
import carrentalsystem.payment.PaymentProcessor;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class CarRentalSystem {
    private static CarRentalSystem instance = new CarRentalSystem();
    private final ConcurrentHashMap<String , Car> cars;
    private final ConcurrentHashMap<String, Reservation> reservations;
    private final PaymentProcessor paymentProcessor;

    private CarRentalSystem() {
        cars = new ConcurrentHashMap<>();
        reservations = new ConcurrentHashMap<>();
        paymentProcessor = new CreditCardPaymentProcessor();
    }

    public static CarRentalSystem getInstance() {
        return instance;
    }

    public void addCar(Car car) {
        cars.put(car.getLicencePlate(), car);
    }
    public void removeCar(Car car) {
        cars.remove(car.getLicencePlate());
    }
    public List<Car> searchCars(String make, String model, LocalDate startDate, LocalDate endDate) {
        List<Car> availableCars = new ArrayList<>();
        for (Car car : cars.values()) {
            if (car.getName().equalsIgnoreCase(make) && car.getModel().equalsIgnoreCase(model) && car.isAvailable()) {
                if (isCarAvailable(car, startDate, endDate)) {
                    availableCars.add(car);
                }
            }
        }
        return availableCars;
    }

    private boolean isCarAvailable(Car car, LocalDate startDate, LocalDate endDate) {
        for (Reservation reservation : reservations.values()) {
            if (reservation.getCar().equals(car)) {
                if (startDate.isBefore(reservation.getEndDate()) && endDate.isAfter(reservation.getStartDate())) {
                    return false;
                }
            }
        }
        return true;
    }

    public synchronized Reservation makeReservation(Customer customer, Car car, LocalDate startDate, LocalDate endDate) {
        if (isCarAvailable(car, startDate, endDate)) {
            String reservationId = generateReservationId();
            Reservation reservation = new Reservation(reservationId, customer, car, startDate, endDate);
            reservations.put(reservationId, reservation);
            car.setAvailable(false);
            return reservation;
        }
        return null;
    }

    public synchronized void cancelReservation(String reservationId) {
        Reservation reservation = reservations.remove(reservationId);
        if (reservation != null) {
            reservation.getCar().setAvailable(true);
        }
    }

    public boolean processPayment(Reservation reservation) {
        return paymentProcessor.processPayment(reservation.getTotalPrice());
    }

    private String generateReservationId() {
        return "RES" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
    }
}
entities/Car.java 38 lines
package carrentalsystem.entities;

public class Car {
    private final String name;
    private final String model;
    private final int year;
    private final String licencePlate;
    private final double pricePerDay;
    private boolean available;

    public Car(String name, String model, int year, String licencePlate, double pricePerDay) {
        this.available = true;
        this.name = name;
        this.year = year;
        this.licencePlate = licencePlate;
        this.pricePerDay = pricePerDay;
        this.model = model;
    }

    public String getName() {
        return name;
    }
    public String getModel() {
        return model;
    }
    public int getYear() {
        return year;
    }
    public String getLicencePlate() {
        return licencePlate;
    }
    public double getPricePerDay() {
        return pricePerDay;
    }
    public boolean isAvailable() {
        return available;
    }

    public void setAvailable(boolean available) {
        this.available = available;
    }
}
entities/Customer.java 11 lines
package carrentalsystem.entities;

public class Customer {
    private final String name;
    private final String driversLicenseNumber;
    private final String contactInfo;

    public Customer(String name, String contactInfo, String driversLicenseNumber) {
        this.name = name;
        this.contactInfo = contactInfo;
        this.driversLicenseNumber = driversLicenseNumber;
    }
}
entities/Reservation.java 39 lines
package carrentalsystem.entities;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

public class Reservation {
    private final String reservationId;
    private final Customer customer;
    private final Car car;
    private final LocalDate startDate;
    private final LocalDate endDate;
    private final double totalPrice;

    public Reservation(String reservationId, Customer customer, Car car, LocalDate startDate, LocalDate endDate) {
        this.reservationId = reservationId;
        this.customer = customer;
        this.car = car;
        this.startDate = startDate;
        this.endDate = endDate;
        this.totalPrice = calculateTotalPrice();
    }

    private double calculateTotalPrice() {
        long daysRented = ChronoUnit.DAYS.between(startDate, endDate) + 1;
        return car.getPricePerDay() * daysRented;
    }

    public LocalDate getStartDate() {
        return startDate;
    }

    public LocalDate getEndDate() {
        return endDate;
    }

    public Car getCar() {
        return car;
    }

    public double getTotalPrice() {
        return totalPrice;
    }

    public String getReservationId() {
        return reservationId;
    }
}
payment/CreditCardPaymentProcessor.java 7 lines
package carrentalsystem.payment;

public class CreditCardPaymentProcessor implements PaymentProcessor{

    @Override
    public boolean processPayment(double amount) {
        return true;
    }
}
payment/PaymentProcessor.java 4 lines
package carrentalsystem.payment;

public interface PaymentProcessor {
    boolean processPayment(double amount);
}
type/CarStatus.java 4 lines
package carrentalsystem.type;

public enum CarStatus {
    AVAILABLE, BOOKED, MAINTENANCE
}
type/CarType.java 4 lines
package carrentalsystem.type;

public enum CarType {
    SUV, SEDAN, HATCHBACK
}
CarRentalSystemDemo.java 38 lines
package carrentalsystem;

import carrentalsystem.entities.Car;
import carrentalsystem.entities.Customer;
import carrentalsystem.entities.Reservation;

import java.time.LocalDate;
import java.util.List;

public class CarRentalSystemDemo {
    public static void main(String[] args) {
        CarRentalSystem carRentalSystem = CarRentalSystem.getInstance();

        // Add cars to the rental system
        carRentalSystem.addCar(new Car("Toyota", "Camry", 2022, "ABC123", 50.0));
        carRentalSystem.addCar(new Car("Honda", "Civic", 2021, "XYZ789", 45.0));
        carRentalSystem.addCar(new Car("Ford", "Mustang", 2023, "DEF456", 80.0));

        // Create customers
        Customer customer1 = new Customer("John Doe", "john@example.com", "DL1234");

        // Make reservations
        LocalDate startDate = LocalDate.now();
        LocalDate endDate = startDate.plusDays(3);
        List<Car> availableCars = carRentalSystem.searchCars("Toyota", "Camry", startDate, endDate);
        if (!availableCars.isEmpty()) {
            Car selectedCar = availableCars.get(0);
            Reservation reservation = carRentalSystem.makeReservation(customer1, selectedCar, startDate, endDate);
            if (reservation != null) {
                boolean paymentSuccess = carRentalSystem.processPayment(reservation);
                if (paymentSuccess) {
                    System.out.println("Reservation successful. Reservation ID: " + reservation.getReservationId());
                } else {
                    System.out.println("Payment failed. Reservation canceled.");
                    carRentalSystem.cancelReservation(reservation.getReservationId());
                }
            } else {
                System.out.println("Selected car is not available for the given dates.");
            }
        } else {
            System.out.println("No available cars found for the given criteria.");
        }
    }
}