车辆租赁服务
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 87 课,共 87 课。
在这个最终挑战中,你将构建一个车辆租赁服务系统,综合运用你在这门课程中掌握的所有面向对象编程(OOP)概念。
你的系统应对不同类型的车辆组成的车队进行建模。可以考虑创建一个基类 Vehicle,包含车牌、品牌和每日租金等常见属性。Car、Motorcycle 和 Truck 等子类可以扩展该类,并添加座位数、发动机排量或载货量等特定属性。
接口可以定义租赁行为:Rentable 接口可以声明 rent()、returnVehicle() 和 calculateCost(int days) 等方法。不同类型的车辆可以采用不同的定价策略,因此这是多态的理想应用场景。
想一想 RentalAgency 类如何使用组合来管理车队。
像 VehicleNotAvailableException 这样的自定义异常可以处理边缘情况。
你可以使用工厂模式来创建车辆,也可以使用枚举表示车辆类别和租赁状态。
这个挑战将测试你设计完整且结构良好的面向对象编程系统的能力。祝你好运!
挑战
简单让我们构建一个完整的车辆租赁服务,把你学过的所有面向对象编程知识结合起来!你将创建一个系统,用于管理不同类型的车辆,进行经过适当验证的租赁操作,并使用工厂模式创建车辆。
你需要将代码分布在 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 或 nullrentVehicle(String licensePlate, int days):查找车辆,尝试租赁(转换为 Rentable),并返回租赁费用。如果未找到车辆,或 rent() 返回 false,则抛出VehicleNotAvailableExceptionreturnVehicle(String licensePlate):查找并归还车辆,成功时返回 truegetAvailableVehicles():返回一个包含状态为 AVAILABLE 的车辆的 ArrayList
Main.java:构建你的租赁服务!你会收到一个以逗号分隔的命令字符串:ADD_CAR:licensePlate:brand:dailyRate:seatsADD_MOTORCYCLE:licensePlate:brand:dailyRate:engineCCRENT:licensePlate:daysRETURN:licensePlateAVAILABLE
处理每条命令并打印:
- 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 ---"
// 然后打印每辆车的详细信息
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器