尧图精选

停车场系统低层设计实战:基于 awesome-low-level-design 的 Java 多楼层停车管理系统

🕒 发布时间:2026/10/2 7:55:26 📁 来源:尧图网络
示例工程【免费下载链接】awesome-low-level-designLearn Low Level Design (LLD) and prepare for interviews using free resources.项目地址https://gitcode.com/GitHub_Trending/aw/awesome-low-level-design点击查看免费下载导读本文以 awesome-low-level-design 仓库中 Java 版停车场系统实现 为主体完整讲解一个支持多楼层、多种车型、多种车位类型、停车出票、自动计费与车位分配策略的停车场管理系统Parking Lot System的低层设计LLD全过程。读完本文你将掌握核心实体ParkingLot / ParkingFloor / ParkingSpot / ParkingTicket的职责划分、Singleton 与 Strategy 两种设计模式在真实业务中的落地方式以及如何通过策略接口低成本扩展新的计费规则与车位分配算法。问题陈述与需求分析仓库内的问题描述文档 problems/parking-lot.md 给出了该系统的需求基线而 Java 实现目录下的 README 对其做了细化综合可归纳为多楼层停车场可以包含多个楼层floor。多车位类型每个楼层拥有多个停车位车位按尺寸分为 SMALL / MEDIUM / LARGE对应代码中的VehicleSize枚举。多车型支持系统需支持轿车Car、摩托车Bike、卡车Truck等不同车型见vehicle/包。出票车辆入场停放后生成一张停车票据ParkingTicket。离场计费车辆离场时释放车位并计算停车费用。灵活的计费策略支持不同的费用计算策略见strategy/fee/。车位分配为车辆分配正确类型且最近/最合适的车位。可扩展性易于新增车型、车位类型或计费策略且不修改既有核心代码。该实现还额外关注了并发安全停车场、楼层、车位、活跃票据集合均使用并发容器或synchronized关键区保护满足多入口多出口并发访问的需求problems/parking-lot.md 第 6 条。核心实体与源码解析系统按职责划分为四个核心实体类与两个支撑包全部位于 solutions/java/src/parkinglot/parkinglot/ ├── ParkingLot.java # 门面/单例管理整体流程 ├── ParkingLotDemo.java # 可运行的演示程序 ├── entities/ │ ├── ParkingFloor.java # 楼层 │ ├── ParkingSpot.java # 车位 │ └── ParkingTicket.java # 停车票据 ├── strategy/ │ ├── fee/ # 计费策略Strategy │ └── parking/ # 车位分配策略Strategy └── vehicle/ # 车型抽象与实现 ├── Vehicle.java VehicleSize.java ├── Bike.java Car.java Truck.java1. ParkingLot全局门面与单例ParkingLot.java 是整个系统的入口类同时演示了懒加载 双重检查的单例模式private static ParkingLot instance; public static synchronized ParkingLot getInstance() { if (instance null) { instance new ParkingLot(); } return instance; }私有构造函数中设置了两套默认策略并把活跃票据放在ConcurrentHashMap中以支持并发访问private ParkingLot() { this.feeStrategy new FlatRateFeeStrategy(); this.parkingStrategy new BestFitStrategy(); this.activeTickets new ConcurrentHashMap(); }对外暴露的核心方法与 README 中列出的方法一一对应addFloor(ParkingFloor floor)添加楼层。parkVehicle(Vehicle vehicle)委托给当前ParkingStrategy查找车位找到则占位、出票并登记到activeTickets以车牌号为 key返回OptionalParkingTicket找不到返回Optional.empty()。unparkVehicle(String licenseNumber)按车牌号README 中写为 ticketId实际实现以车牌号为索引取出票据记录离场时间、释放车位并调用FeeStrategy.calculateFee(ticket)计算费用。setFeeStrategy / setParkingStrategy运行时热切换计费与分配策略这正是策略模式的用武之地。从源码结构看README 中unparkVehicle(String ticketId)的签名与实现存在差异当前实现以licenseNumber作为活跃票据的查找键这是阅读与使用源码时需要注意的细节。2. ParkingFloor楼层内的车位管理ParkingFloor.java 持有floorNumber与一个ConcurrentHashMapString, ParkingSpot车位集合提供addSpot(ParkingSpot spot)以spotId为 key 登记车位。findAvailableSpot(Vehicle vehicle)过滤出空闲且能容纳该车辆的车位并按车位尺寸 ordinal 升序排序取第一个即楼层内天然执行最贴合分配public synchronized OptionalParkingSpot findAvailableSpot(Vehicle vehicle) { return spots.values().stream() .filter(spot - !spot.isOccupied() spot.canFitVehicle(vehicle)) .sorted(Comparator.comparing(ParkingSpot::getSpotSize)) .findFirst(); }displayAvailability()按VehicleSize分组统计各尺寸空闲车位数便于演示与实时信息展示。3. ParkingSpot车位状态机ParkingSpot.java 记录spotId、spotSize、占用标志与当前停放车辆。关键的车型-车位匹配规则canFitVehicle如下switch (vehicle.getSize()) { case SMALL: return spotSize VehicleSize.SMALL; case MEDIUM: return spotSize VehicleSize.MEDIUM || spotSize VehicleSize.LARGE; case LARGE: return spotSize VehicleSize.LARGE; }即小型车只能停小型位中型车可停中型或大型位向下兼容大型车只能停大型位。所有状态变更方法parkVehicle/unparkVehicle/isAvailable均加synchronized保证同一车位的并发互斥。4. ParkingTicket停车凭证ParkingTicket.java 在车辆成功停放时生成字段包括ticketId由UUID.randomUUID().toString()生成的全局唯一票据号。vehicle/spot车辆信息与所停车位。entryTimestamp入场时间戳new Date().getTime()票据创建时固化。exitTimestamp由setExitTimestamp()在离场时写入作为计费时长依据。5. 车型体系Vehicle 抽象基类 VehicleSize 枚举Vehicle.java 是抽象基类持有不可变的licenseNumber与size三个子类只负责在构造时声明自身尺寸public class Bike extends Vehicle { public Bike(String licenseNumber) { super(licenseNumber, VehicleSize.SMALL); } } public class Car extends Vehicle { public Car(String licenseNumber) { super(licenseNumber, VehicleSize.MEDIUM); } } public class Truck extends Vehicle { public Truck(String licenseNumber) { super(licenseNumber, VehicleSize.LARGE); } }VehicleSize.java 定义SMALL / MEDIUM / LARGE三个枚举值其ordinal()还被BestFitStrategy用于比较车位贴合程度。策略模式一计费策略计费模块遵循策略模式接口与实现位于 strategy/fee/public interface FeeStrategy { double calculateFee(ParkingTicket parkingTicket); }仓库内置两种实现可通过parkingLot.setFeeStrategy(...)随时切换策略计费规则说明FlatRateFeeStrategy统一费率RATE_PER_HOUR 10.0计费小时 (时长/3600000) 1费用 小时 × 10简单统一价按整小时向上取整VehicleBasedFeeStrategy按车型分档SMALL 10 / MEDIUM 20 / LARGE 30 元每小时计费小时同上费率取HOURLY_RATES.get(vehicle.getSize())两种实现均使用(duration / (1000 * 60 * 60)) 1将毫秒时长折算为至少 1 小时的整小时数——即使停车不足 1 分钟也按 1 小时计费这是实际停车系统中常见的取整口径也是扩展自定义策略时可直接复用的模板。策略模式二车位分配策略车位分配同样抽象为策略接口 ParkingStrategy.javapublic interface ParkingStrategy { OptionalParkingSpot findSpot(ListParkingFloor floors, Vehicle vehicle); }仓库内置三种分配算法覆盖了最常见的停车需求BestFitStrategy默认遍历所有楼层在能容纳该车辆的车位中挑选尺寸 ordinal 最小者即最贴合、最节省大车位的分配仅在没有找到任何可用车位时返回空。NearestFirstStrategy按楼层列表顺序从前向后查找返回第一个能容纳的可用车位——模拟离入口最近优先。FarthestFirstStrategy反转楼层列表从最远楼层开始找——常用于引导车辆优先停满远端、为入口留位。注意三种策略最终都会调用ParkingFloor.findAvailableSpot()因此楼层内部始终按尺寸最贴合过滤策略之间的差异体现在楼层遍历顺序从头 / 从尾 / 全局最优上。设计模式总结模式落点源码依据Singleton全局唯一的ParkingLot实例ParkingLot.java#L16-L33synchronized getInstance()懒加载Strategy计费策略与车位分配策略双维度解耦FeeStrategy.java、ParkingStrategy.javaTemplate Method轻量Vehicle抽象基类固化构造流程子类仅声明尺寸Vehicle.javaFactory可选扩展可依据输入创建对应车型问题文档中列为可选扩展当前实现由 Demo 直接new Car(...)README 提到的Observer 可选扩展车位空闲通知客户在问题文档 problems/parking-lot.md 中亦有提及可作为面试时的加分演进方向当前代码未实现。完整示例从初始化到收费的端到端流程ParkingLotDemo.java 是官方演示程序其流程完整覆盖初始化 → 入场 → 分配 → 离场计费可与上文各实体一一对应ParkingLot parkingLot ParkingLot.getInstance(); // 1. 楼层与车位初始化 ParkingFloor floor1 new ParkingFloor(1); floor1.addSpot(new ParkingSpot(F1-S1, VehicleSize.SMALL)); floor1.addSpot(new ParkingSpot(F1-M1, VehicleSize.MEDIUM)); floor1.addSpot(new ParkingSpot(F1-L1, VehicleSize.LARGE)); ParkingFloor floor2 new ParkingFloor(2); floor2.addSpot(new ParkingSpot(F2-M1, VehicleSize.MEDIUM)); floor2.addSpot(new ParkingSpot(F2-M2, VehicleSize.MEDIUM)); parkingLot.addFloor(floor1); parkingLot.addFloor(floor2); // 2. 切换到按车型计费 parkingLot.setFeeStrategy(new VehicleBasedFeeStrategy()); // 3. 入场自行车 / 轿车 / 卡车 parkingLot.parkVehicle(new Bike(B-123)); parkingLot.parkVehicle(new Car(C-456)); parkingLot.parkVehicle(new Truck(T-789)); // 4. 离场并计费 parkingLot.unparkVehicle(C-456);结合源码可以推演其运行结果Bike(B-123)SMALL→ 命中F1-S1Car(C-456)MEDIUM→ 命中F1-M1Truck(T-789)LARGE→ 命中F1-L1。Car(C-999)MEDIUM在默认BestFitStrategy下一楼 MEDIUM 位已被占用、无其他可容纳位于是落到二楼的F2-M1——验证了跨楼层全局分配。Bike(B-000)SMALL入场时一楼 SMALL 位已占用、二楼根本没有 SMALL 车位分配失败输出No available spot for B-000——验证了Optional.empty()的优雅降级。unparkVehicle(C-456)后按VehicleBasedFeeStrategy计费Demo 中车辆即时出入时长不足 1 小时按 1 小时计MEDIUM 费率 20.0费用为$20.00随后F1-M1恢复空闲。如何运行在仓库根目录执行以下命令即可编译并运行该 Java 实现要求已安装 JDK 8cd solutions/java/src/parkinglot javac ParkingLotDemo.java parkinglot/entities/*.java parkinglot/strategy/fee/*.java parkinglot/strategy/parking/*.java parkinglot/vehicle/*.java java parkinglot.ParkingLotDemo程序会依次打印入场日志、各楼层可用性统计按 SMALL/MEDIUM/LARGE 分组计数以及离场费用读者可据此对照验证每种策略的行为差异。扩展框架指南README 给出了三条清晰的扩展路径均以新增类而非改动既有类为原则正是 Strategy/模板方法解耦的价值所在新增车型在 vehicle/ 下新增Vehicle子类构造时声明对应的VehicleSize若引入新尺寸需同步扩展VehicleSize枚举与 ParkingSpot.canFitVehicle() 的匹配逻辑。新增计费策略实现 FeeStrategy 接口如夜间优惠、时长阶梯价再通过parkingLot.setFeeStrategy(...)注入即可ParkingLot 与票据类零改动。新增车位类型或楼层行为扩展 ParkingSpot如加电动车充电位或 ParkingFloor若要引入新的分配语义只需实现 ParkingStrategy 并注入。小结该 Java 版停车场系统是一个教科书级的 LLD 范例Singleton 保证全局唯一实例Strategy 双维度计费 分配解耦算法与业务并发容器与 synchronized 支撑多入口场景Optional 返回值让无位可停成为可预期的业务结果。读者可以对照 class-diagrams/parkinglot-class-diagram.png 中的 UML 类图梳理类间关系再结合 ParkingLotDemo.java 实际运行即可完整掌握从需求分析到可扩展代码实现的全链路方法。赞分享示例工程【免费下载链接】awesome-low-level-designLearn Low Level Design (LLD) and prepare for interviews using free resources.项目地址https://gitcode.com/GitHub_Trending/aw/awesome-low-level-design点击查看免费下载相关推荐停车管理系统Parking Lot低层设计实战指南基于 awesome-low-level-design 的面向对象设计解析停车管理系统Parking Lot低层设计实战指南基于 awesome low level design 的面向对象设计解析 导读 本文围绕 proble示例工程停车场系统低层设计LLD实战C 源码解析与多线程扩展awesome-low-level-design停车场系统低层设计LLD实战C 源码解析与多线程扩展awesome low level design 导读本文以 awesome low level示例工程用 Go 实现停车场系统面向面试的低层设计Low-Level Design实战指南用 Go 实现停车场系统面向面试的低层设计Low Level Design实战指南 本篇文章以本仓库 solutions/golang/parkinglo示例工程上一篇lua-resty-kafka安装与部署从源码编译到生产环境配置下一篇RestfulToolkitX 开源项目安装与使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →