Java面向对象实战:手把手教你用继承和多态打造租车系统(附完整代码)
Java面向对象实战:从零构建租车系统的继承与多态设计
租车系统是学习面向对象编程(OOP)的绝佳案例。这个看似简单的业务场景,实际上涵盖了类设计、继承体系、多态应用等核心概念。我们将从零开始,构建一个完整的租车系统,重点讲解如何用Java实现优雅的面向对象设计。
1. 系统分析与类设计
在动手编码之前,我们需要对租车业务进行充分分析。一个典型的租车系统包含以下核心要素:
- 车辆类型:客车、货车、皮卡等不同车型
- 租赁属性:租金计算、租期管理
- 载客/载货能力:不同车型的运输特性
- 业务规则:费用计算、可用性检查等
基于这些分析,我们可以设计出以下类结构:
// 基类:车辆 abstract class Vehicle { private String model; private double dailyRate; public Vehicle(String model, double dailyRate) { this.model = model; this.dailyRate = dailyRate; } public double calculateRentalFee(int days) { return days * dailyRate; } // 抽象方法,子类必须实现 public abstract String getCapacityDescription(); } // 客车类 class PassengerCar extends Vehicle { private int passengerCapacity; public PassengerCar(String model, double dailyRate, int passengerCapacity) { super(model, dailyRate); this.passengerCapacity = passengerCapacity; } @Override public String getCapacityDescription() { return "载客量: " + passengerCapacity + "人"; } } // 货车类 class Truck extends Vehicle { private double cargoCapacity; // 吨 public Truck(String model, double dailyRate, double cargoCapacity) { super(model, dailyRate); this.cargoCapacity = cargoCapacity; } @Override public String getCapacityDescription() { return "载货量: " + cargoCapacity + "吨"; } } // 皮卡类 class PickupTruck extends Vehicle { private int passengerCapacity; private double cargoCapacity; public PickupTruck(String model, double dailyRate, int passengerCapacity, double cargoCapacity) { super(model, dailyRate); this.passengerCapacity = passengerCapacity; this.cargoCapacity = cargoCapacity; } @Override public String getCapacityDescription() { return "载客量: " + passengerCapacity + "人, 载货量: " + cargoCapacity + "吨"; } }2. 多态在租车系统中的应用
多态是OOP的三大特性之一,它允许我们以统一的方式处理不同类型的对象。在我们的租车系统中,多态主要体现在:
- 统一接口:所有车辆都继承自Vehicle基类
- 动态绑定:运行时确定调用哪个子类的方法
- 扩展性:新增车型不影响现有代码
下面是一个展示多态优势的示例:
public class RentalSystem { private List<Vehicle> fleet = new ArrayList<>(); public void initializeFleet() { fleet.add(new PassengerCar("商务轿车", 500, 5)); fleet.add(new Truck("厢式货车", 800, 3.5)); fleet.add(new PickupTruck("皮卡", 600, 4, 1.5)); } public void displayFleetInfo() { for (Vehicle vehicle : fleet) { System.out.println(vehicle.getModel() + " - " + vehicle.getCapacityDescription()); } } public double calculateTotalRental(Vehicle vehicle, int days) { return vehicle.calculateRentalFee(days); } }在这个设计中,calculateTotalRental方法可以接受任何Vehicle子类的实例,系统会自动调用正确的计算方法,这就是多态的威力。
3. 系统功能实现与业务逻辑
现在我们来实现租车系统的核心业务逻辑。系统需要处理以下功能:
- 车辆选择与组合
- 租期计算
- 费用汇总
- 载客/载货能力统计
以下是核心业务类的实现:
public class RentalService { private List<Vehicle> availableVehicles; private List<RentalItem> currentRental = new ArrayList<>(); public RentalService(List<Vehicle> availableVehicles) { this.availableVehicles = availableVehicles; } public void addToRental(int vehicleIndex, int days) { if (vehicleIndex >= 0 && vehicleIndex < availableVehicles.size()) { currentRental.add(new RentalItem(availableVehicles.get(vehicleIndex), days)); } } public RentalSummary calculateSummary() { int totalPassengers = 0; double totalCargo = 0.0; double totalCost = 0.0; for (RentalItem item : currentRental) { Vehicle vehicle = item.getVehicle(); int days = item.getDays(); totalCost += vehicle.calculateRentalFee(days); if (vehicle instanceof PassengerCar) { totalPassengers += ((PassengerCar) vehicle).getPassengerCapacity() * days; } else if (vehicle instanceof Truck) { totalCargo += ((Truck) vehicle).getCargoCapacity() * days; } else if (vehicle instanceof PickupTruck) { PickupTruck pickup = (PickupTruck) vehicle; totalPassengers += pickup.getPassengerCapacity() * days; totalCargo += pickup.getCargoCapacity() * days; } } return new RentalSummary(totalPassengers, totalCargo, totalCost); } } class RentalItem { private Vehicle vehicle; private int days; public RentalItem(Vehicle vehicle, int days) { this.vehicle = vehicle; this.days = days; } // getters... } class RentalSummary { private int totalPassengers; private double totalCargo; private double totalCost; public RentalSummary(int totalPassengers, double totalCargo, double totalCost) { this.totalPassengers = totalPassengers; this.totalCargo = totalCargo; this.totalCost = totalCost; } @Override public String toString() { return String.format("总载客: %d人, 总载货: %.2f吨, 总费用: %.2f元", totalPassengers, totalCargo, totalCost); } }4. 用户交互与系统集成
为了让系统真正可用,我们需要实现用户交互层。这里我们采用控制台界面,但设计上保持业务逻辑与界面分离,便于未来扩展。
public class RentalApp { private RentalService rentalService; private Scanner scanner; public RentalApp() { initializeVehicles(); this.scanner = new Scanner(System.in); } private void initializeVehicles() { List<Vehicle> vehicles = new ArrayList<>(); vehicles.add(new PassengerCar("商务轿车", 500, 5)); vehicles.add(new PassengerCar("中巴车", 800, 15)); vehicles.add(new Truck("小型货车", 600, 2.0)); vehicles.add(new Truck("大型货车", 1200, 10.0)); vehicles.add(new PickupTruck("标准皮卡", 450, 4, 1.5)); this.rentalService = new RentalService(vehicles); } public void start() { displayWelcomeMessage(); displayVehicleList(); boolean renting = true; while (renting) { System.out.print("\n请输入要租赁的车辆编号(0结束): "); int choice = scanner.nextInt(); if (choice == 0) { renting = false; } else { System.out.print("请输入租赁天数: "); int days = scanner.nextInt(); rentalService.addToRental(choice - 1, days); } } displayRentalSummary(); } private void displayWelcomeMessage() { System.out.println("=== 欢迎使用租车系统 ==="); System.out.println("以下是可租车辆列表:"); } private void displayVehicleList() { List<Vehicle> vehicles = rentalService.getAvailableVehicles(); for (int i = 0; i < vehicles.size(); i++) { Vehicle v = vehicles.get(i); System.out.printf("%d. %s - %s - 每日租金: %.2f元\n", i + 1, v.getModel(), v.getCapacityDescription(), v.getDailyRate()); } } private void displayRentalSummary() { RentalSummary summary = rentalService.calculateSummary(); System.out.println("\n=== 租赁汇总 ==="); System.out.println(summary); } public static void main(String[] args) { new RentalApp().start(); } }5. 高级主题与系统扩展
我们的基础系统已经完成,但一个真正的商业系统还需要考虑更多因素。以下是几个可能的扩展方向:
5.1 价格策略模式
不同车型、不同租期可能有不同的计价策略。我们可以使用策略模式来实现灵活的价格计算:
interface PricingStrategy { double calculatePrice(double baseRate, int days); } class StandardPricing implements PricingStrategy { public double calculatePrice(double baseRate, int days) { return baseRate * days; } } class WeeklyDiscountPricing implements PricingStrategy { public double calculatePrice(double baseRate, int days) { int weeks = days / 7; int remainingDays = days % 7; return (weeks * baseRate * 6) + (remainingDays * baseRate); } } class Vehicle { private PricingStrategy pricingStrategy = new StandardPricing(); public void setPricingStrategy(PricingStrategy strategy) { this.pricingStrategy = strategy; } public double calculateRentalFee(int days) { return pricingStrategy.calculatePrice(dailyRate, days); } }5.2 车辆状态管理
实际租车系统中,车辆可能有多种状态(可用、维修中、已租出等)。我们可以引入状态模式:
interface VehicleState { boolean isAvailable(); VehicleState rent(); VehicleState returnVehicle(); VehicleState sendForMaintenance(); } class AvailableState implements VehicleState { public boolean isAvailable() { return true; } public VehicleState rent() { return new RentedState(); } // 其他方法实现... } class Vehicle { private VehicleState state = new AvailableState(); public boolean isAvailable() { return state.isAvailable(); } public void rent() { state = state.rent(); } }5.3 数据库集成与持久化
实际应用中,车辆数据应该存储在数据库中。我们可以使用JDBC或JPA来实现:
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "vehicle_type") public abstract class Vehicle { @Id @GeneratedValue private Long id; private String model; private double dailyRate; // ... } @Entity @DiscriminatorValue("PASSENGER") public class PassengerCar extends Vehicle { private int passengerCapacity; // ... } public class VehicleRepository { @PersistenceContext private EntityManager em; public List<Vehicle> findAllAvailable() { return em.createQuery( "SELECT v FROM Vehicle v WHERE v.available = true", Vehicle.class) .getResultList(); } }6. 测试与验证
完善的测试是保证系统质量的关键。我们可以为系统编写单元测试和集成测试:
public class RentalServiceTest { private RentalService rentalService; @Before public void setUp() { List<Vehicle> vehicles = Arrays.asList( new PassengerCar("Test Car", 100, 4), new Truck("Test Truck", 200, 2.0) ); rentalService = new RentalService(vehicles); } @Test public void testPassengerCarRental() { rentalService.addToRental(0, 3); // 租用客车3天 RentalSummary summary = rentalService.calculateSummary(); assertEquals(12, summary.getTotalPassengers()); // 4人×3天 assertEquals(0.0, summary.getTotalCargo(), 0.01); assertEquals(300.0, summary.getTotalCost(), 0.01); } @Test public void testMixedRental() { rentalService.addToRental(0, 2); // 客车2天 rentalService.addToRental(1, 1); // 货车1天 RentalSummary summary = rentalService.calculateSummary(); assertEquals(8, summary.getTotalPassengers()); // 4人×2天 assertEquals(2.0, summary.getTotalCargo(), 0.01); // 2吨×1天 assertEquals(400.0, summary.getTotalCost(), 0.01); // 100×2 + 200×1 } }在实际项目中,我们还会考虑添加日志记录、异常处理、输入验证等功能,使系统更加健壮。
