Menu
CoddyTech

车辆租赁服务

本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 87 课,共 87 课。

在这个最终挑战中,你将构建一个车辆租赁服务系统,综合运用你在这门课程中掌握的所有面向对象编程(OOP)概念。

你的系统应对不同类型的车辆组成的车队进行建模。可以考虑创建一个基类 Vehicle,包含车牌、品牌和每日租金等常见属性。Car、Motorcycle 和 Truck 等子类可以扩展该类,并添加座位数、发动机排量或载货量等特定属性。

接口可以定义租赁行为:Rentable 接口可以声明 rent()、returnVehicle() 和 calculateCost(int days) 等方法。不同类型的车辆可以采用不同的定价策略,因此这是多态的理想应用场景。

想一想 RentalAgency 类如何使用组合来管理车队。

像 VehicleNotAvailableException 这样的自定义异常可以处理边缘情况。

你可以使用工厂模式来创建车辆,也可以使用枚举表示车辆类别和租赁状态。

这个挑战将测试你设计完整且结构良好的面向对象编程系统的能力。祝你好运!

challenge icon

挑战

简单

让我们构建一个完整的车辆租赁服务,把你学过的所有面向对象编程知识结合起来!你将创建一个系统,用于管理不同类型的车辆,进行经过适当验证的租赁操作,并使用工厂模式创建车辆。

你需要将代码分布在 7 个文件中:

  • RentalStatus.java:创建一个枚举,表示车辆的租赁状态。包含值 AVAILABLE、RENTED 和 MAINTENANCE。添加一个私有字段 description(String)、一个构造函数和一个 getter。AVAILABLE 的描述应为 "ready to rent",RENTED 的描述应为 "currently in use",MAINTENANCE 的描述应为 "under service"。
  • VehicleNotAvailableException.java:创建一个继承自 Exception 的自定义异常。构造函数应接收车牌号,并创建格式为 Vehicle not available: [licensePlate] 的消息。
  • Rentable.java:创建一个定义租赁操作的接口。声明方法 rent(),返回 boolean;returnVehicle(),返回 boolean;以及 calculateCost(int days),返回 double。
  • Vehicle.java:为所有车辆创建一个抽象基类。添加以下私有字段:licensePlate(String)、brand(String)、dailyRate(double)和 status(RentalStatus,初始化为 AVAILABLE)。构造函数接收 licensePlate、brand 和 dailyRate。添加适当的 getter,以及用于设置 status 的 setter。声明一个返回 String 的抽象方法 getVehicleType()。实现方法 getDetails(),返回 "[licensePlate] [brand] ([vehicleType]) - $[dailyRate]/day - [status description]",其中 dailyRate 格式化为 2 位小数。
  • Car.java:创建一个继承 Vehicle 并实现 Rentable 的类。添加一个私有字段 seats(int)。构造函数接收 licensePlate、brand、dailyRate 和 seats。实现 getVehicleType(),使其返回 "Car"。对于 rent(),如果状态为 AVAILABLE,就将状态设为 RENTED 并返回 true;否则返回 false。对于 returnVehicle(),如果状态为 RENTED,就将状态设为 AVAILABLE 并返回 true;否则返回 false。对于 calculateCost(int days),返回 dailyRate 乘以天数。
  • Motorcycle.java:创建一个继承 Vehicle 并实现 Rentable 的类。添加一个私有字段 engineCC(int)。构造函数接收 licensePlate、brand、dailyRate 和 engineCC。实现 getVehicleType(),使其返回 "Motorcycle"。以与 Car 相同的方式实现 Rentable 方法,但 calculateCost() 应提供 10% 的折扣(乘以 0.9)。
  • RentalAgency.java:创建一个使用 ArrayList 管理车辆队列的类。添加以下方法:
    • addVehicle(Vehicle vehicle):将车辆添加到队列中
    • findVehicle(String licensePlate):返回 Vehicle 或 null
    • rentVehicle(String licensePlate, int days):查找车辆,尝试租赁(转换为 Rentable),并返回租赁费用。如果未找到车辆,或 rent() 返回 false,则抛出 VehicleNotAvailableException
    • returnVehicle(String licensePlate):查找并归还车辆,成功时返回 true
    • getAvailableVehicles():返回一个包含状态为 AVAILABLE 的车辆的 ArrayList
  • Main.java:构建你的租赁服务!你会收到一个以逗号分隔的命令字符串:
    • ADD_CAR:licensePlate:brand:dailyRate:seats
    • ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC
    • RENT:licensePlate:days
    • RETURN:licensePlate
    • AVAILABLE

    处理每条命令并打印:

    • ADD_CAR/ADD_MOTORCYCLE:Added: [brand] ([vehicleType])
    • RENT:Rented [licensePlate] for [days] days - Total: $[cost](费用保留 2 位小数),或 Error: [exception message]
    • RETURN:Returned: [licensePlate] 或 Return failed: [licensePlate]
    • AVAILABLE:打印 Available vehicles:,然后每行打印一辆可用车辆的详情

    处理完所有命令后,打印 --- Fleet Summary ---,然后打印每辆车的详情。

你会收到一个输入:以逗号分隔的命令字符串。

例如,输入 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 时,输出为:

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 rent

这个挑战将继承(Vehicle 层次结构)、接口(Rentable)、枚举(RentalStatus)、自定义异常、多态(统一处理不同车辆类型)和组合(RentalAgency 管理车辆)结合起来,构建一个完整的车辆租赁服务系统!

亲手试试

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: 创建一个 RentalAgency 实例
        
        // TODO: 按逗号拆分输入,得到各条命令
        
        // TODO: 处理每条命令:
        // ADD_CAR:licensePlate:brand:dailyRate:seats -> 打印 "Added: [brand] ([vehicleType])"
        // ADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCC -> 打印 "Added: [brand] ([vehicleType])"
        // RENT:licensePlate:days -> 打印 "Rented [licensePlate] for [days] days - Total: $[cost]"(保留 2 位小数)
        //                           如果抛出异常,则打印 "Error: [exception message]"
        // RETURN:licensePlate -> 打印 "Returned: [licensePlate]" 或 "Return failed: [licensePlate]"
        // AVAILABLE -> 打印 "Available vehicles:",然后打印每辆可租车辆的详细信息
        
        // TODO: 处理完所有命令后,打印 "--- Fleet Summary ---"
        // 然后打印每辆车的详细信息
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Java 在线编译器