Vehicle Rental Service
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 87 of 87.
For this final challenge, you'll build a Vehicle Rental Service system that brings together all the OOP concepts you've mastered throughout this course.
Your system should model a fleet of different vehicle types. Consider a base Vehicle class with common properties like license plate, brand, and daily rental rate. Subclasses such as Car, Motorcycle, and Truck can extend this with specific attributes like number of seats, engine size, or cargo capacity.
Interfaces can define rental behaviors: a Rentable interface might declare methods like rent(), returnVehicle(), and calculateCost(int days). Different vehicle types could implement pricing strategies differently, making this a perfect use case for polymorphism.
Think about how a RentalAgency class manages the fleet using composition.
Custom exceptions like VehicleNotAvailableException can handle edge cases.
You might apply the Factory pattern to create vehicles or use enums for vehicle categories and rental status.
This challenge tests your ability to design a complete, well-structured OOP system. Good luck!
Challenge
EasyLet's build a complete Vehicle Rental Service that brings together everything you've learned about OOP! You'll create a system that manages a fleet of different vehicle types, handles rentals with proper validation, and uses a factory pattern to create vehicles.
You'll organize your code across seven files:
RentalStatus.java: Create an enum representing the rental status of a vehicle. Include valuesAVAILABLE,RENTED, andMAINTENANCE. Add a private fielddescription(String), a constructor, and a getter. Available should have description "ready to rent", rented should have "currently in use", and maintenance should have "under service".VehicleNotAvailableException.java: Create a custom exception that extendsException. The constructor should accept a license plate and create a message in the formatVehicle not available: [licensePlate].Rentable.java: Create an interface defining rental operations. Declare methodsrent()returning a boolean,returnVehicle()returning a boolean, andcalculateCost(int days)returning a double.Vehicle.java: Create an abstract base class for all vehicles. Include private fields forlicensePlate(String),brand(String),dailyRate(double), andstatus(RentalStatus, initialized to AVAILABLE). The constructor takes licensePlate, brand, and dailyRate. Include appropriate getters and a setter for status. Declare an abstract methodgetVehicleType()returning a String. Implement agetDetails()method that returns"[licensePlate] [brand] ([vehicleType]) - $[dailyRate]/day - [status description]"with dailyRate formatted to 2 decimal places.Car.java: Create a class extending Vehicle and implementing Rentable. Add a private fieldseats(int). The constructor takes licensePlate, brand, dailyRate, and seats. ImplementgetVehicleType()to return"Car". Forrent(), if status is AVAILABLE, set it to RENTED and return true; otherwise return false. ForreturnVehicle(), if status is RENTED, set it to AVAILABLE and return true; otherwise return false. ForcalculateCost(int days), return dailyRate times days.Motorcycle.java: Create a class extending Vehicle and implementing Rentable. Add a private fieldengineCC(int). The constructor takes licensePlate, brand, dailyRate, and engineCC. ImplementgetVehicleType()to return"Motorcycle". Implement the Rentable methods the same way as Car, butcalculateCost()should apply a 10% discount (multiply by 0.9).RentalAgency.java: Create a class that manages the vehicle fleet using an ArrayList. Include methods:addVehicle(Vehicle vehicle)- adds a vehicle to the fleetfindVehicle(String licensePlate)- returns the Vehicle or nullrentVehicle(String licensePlate, int days)- finds the vehicle, attempts to rent it (casting to Rentable), and returns the rental cost. ThrowVehicleNotAvailableExceptionif the vehicle isn't found or if rent() returns falsereturnVehicle(String licensePlate)- finds and returns the vehicle, returning true on successgetAvailableVehicles()- returns an ArrayList of vehicles with AVAILABLE status
Main.java: Build your rental service! You'll receive a comma-separated string of commands:ADD_CAR:licensePlate:brand:dailyRate:seatsADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCCRENT:licensePlate:daysRETURN:licensePlateAVAILABLE
Process each command and print:
- ADD_CAR/ADD_MOTORCYCLE:
Added: [brand] ([vehicleType]) - RENT:
Rented [licensePlate] for [days] days - Total: $[cost](cost to 2 decimals), orError: [exception message] - RETURN:
Returned: [licensePlate]orReturn failed: [licensePlate] - AVAILABLE: Print
Available vehicles:followed by each available vehicle's details on separate lines
After all commands, print
--- Fleet Summary ---followed by each vehicle's details.
You will receive one input: the comma-separated command string.
For example, with input ADD_CAR:ABC-123:Toyota:50.00:5,ADD_MOTORCYCLE:XYZ-789:Honda:40.00:600,RENT:ABC-123:3,RENT:ABC-123:2,AVAILABLE,RETURN:ABC-123, your output would be:
Added: Toyota (Car)
Added: Honda (Motorcycle)
Rented ABC-123 for 3 days - Total: $150.00
Error: Vehicle not available: ABC-123
Available vehicles:
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rent
Returned: ABC-123
--- Fleet Summary ---
ABC-123 Toyota (Car) - $50.00/day - ready to rent
XYZ-789 Honda (Motorcycle) - $40.00/day - ready to rentThis challenge combines inheritance (Vehicle hierarchy), interfaces (Rentable), enums (RentalStatus), custom exceptions, polymorphism (treating different vehicle types uniformly), and composition (RentalAgency managing vehicles) into a complete rental service system!
Cheat sheet
This final challenge combines multiple OOP concepts into a complete system. Here are the key patterns and techniques:
Enums with Fields
Enums can have fields, constructors, and methods:
public enum RentalStatus {
AVAILABLE("ready to rent"),
RENTED("currently in use");
private String description;
private RentalStatus(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}Custom Exceptions
Create domain-specific exceptions by extending Exception:
public class VehicleNotAvailableException extends Exception {
public VehicleNotAvailableException(String licensePlate) {
super("Vehicle not available: " + licensePlate);
}
}Abstract Base Classes with Interfaces
Combine abstract classes for shared implementation with interfaces for behavior contracts:
public abstract class Vehicle {
private String licensePlate;
private RentalStatus status;
public abstract String getVehicleType();
public String getDetails() {
return licensePlate + " " + getVehicleType() + " - " + status.getDescription();
}
}
public interface Rentable {
boolean rent();
boolean returnVehicle();
double calculateCost(int days);
}
public class Car extends Vehicle implements Rentable {
public boolean rent() {
if (getStatus() == RentalStatus.AVAILABLE) {
setStatus(RentalStatus.RENTED);
return true;
}
return false;
}
}Composition for Management
Use composition to manage collections of objects:
public class RentalAgency {
private ArrayList<Vehicle> fleet = new ArrayList<>();
public void addVehicle(Vehicle vehicle) {
fleet.add(vehicle);
}
public double rentVehicle(String licensePlate, int days) throws VehicleNotAvailableException {
Vehicle vehicle = findVehicle(licensePlate);
if (vehicle == null) {
throw new VehicleNotAvailableException(licensePlate);
}
Rentable rentable = (Rentable) vehicle;
if (!rentable.rent()) {
throw new VehicleNotAvailableException(licensePlate);
}
return rentable.calculateCost(days);
}
}Polymorphism in Action
Different subclasses can implement interface methods differently:
// Car: standard pricing
public double calculateCost(int days) {
return dailyRate * days;
}
// Motorcycle: discounted pricing
public double calculateCost(int days) {
return dailyRate * days * 0.9;
}Try it yourself
import java.util.Scanner;
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Create a RentalAgency instance
// TODO: Split the input by comma to get individual commands
// TODO: Process each command:
// ADD_CAR:licensePlate:brand:dailyRate:seats -> print "Added: [brand] ([vehicleType])"
// ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC -> print "Added: [brand] ([vehicleType])"
// RENT:licensePlate:days -> print "Rented [licensePlate] for [days] days - Total: $[cost]" (2 decimals)
// or "Error: [exception message]" if exception thrown
// RETURN:licensePlate -> print "Returned: [licensePlate]" or "Return failed: [licensePlate]"
// AVAILABLE -> print "Available vehicles:" followed by each available vehicle's details
// TODO: After all commands, print "--- Fleet Summary ---"
// followed by each vehicle's details
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System