ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

电影票预订系统低层设计(LLD):需求建模、并发座位锁与设计模式实战(Java 实现)

电影票预订系统低层设计(LLD):需求建模、并发座位锁与设计模式实战(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点击查看免费下载本篇文章基于 awesome-low-level-design 仓库中 Movie Ticket Booking System 的完整低层设计LLD实战文档 solutions/java/src/movieticketbookingsystem/README.md结合其 Java 源码实现系统讲解从需求分析、核心实体建模、并发座位锁、预订业务流程到设计模式落地的全过程。读完本文你将掌握如何用面向对象设计、Singleton/Builder/Observer/Strategy 等模式与基于锁的并发控制构建一个可扩展、可演示的电影票预订系统并能直接运行仓库中附带的完整 Demo。一、问题陈述与需求分析1.1 问题陈述设计并实现一个电影票预订系统Movie Ticket Booking System允许用户预订电影票、选择座位并管理场次Show。系统需要覆盖电影排片、影院管理以及座位预订三大核心域。1.2 需求清单原文档将需求划分为五大模块这是整个设计的骨架电影管理Movie Management存储电影信息片名 title、时长 duration、语言 language管理电影排片与场次schedule show追踪电影的可上映状态availability影院管理Theater Management管理影院基本信息每个影院承载多个场次追踪影院的容纳能力capacity场次管理Show Management为电影排定场次管理场次时间处理场次可用性座位管理Seat Management追踪座位可用性处理座位选择管理不同座位类型REGULAR / PREMIUM预订管理Booking Management处理票务预订流程处理预订取消管理预订状态从源码结构看需求在落地时被进一步细化文档中的「Theater」在实现中被拆分为City城市→Cinema影院→Screen影厅三级结构Show挂在Screen之下座位归属Screen并新增Payment支付实体与SeatLockManager座位锁管理器来支撑预订与并发控制。二、核心实体设计Entity Model2.1 文档定义的实体骨架原文档定义了 5 个核心实体及其职责实体关键字段关键方法职责MovieTicketBookingSystemListMovie、ListTheater、ListShowaddMovie()、addTheater()、addShow()、bookTicket()、cancelBooking()、getAvailableShows()系统门面统筹各领域操作Movieid、title、duration、languagegetShows()、isAvailable()电影信息与排片查询Theaterid、name、locationaddShow()、getShows()、getCapacity()影院信息与场次管理Showid、Movie、Theater、Date showTime、ListSeatgetAvailableSeats()、bookSeat()、cancelSeat()一次具体放映的场次Userid、name、emailgetBookings()、updateProfile()用户资料与历史订单2.2 源码中的实体落地比文档更进一步在 entities 目录 中实体被实现为 9 个 Java 类比文档骨架更贴近真实业务Movie持有id、title、durationInMinutes并继承自MovieSubject观察者模式的被观察对象见 Movie.java。注释明确说明语言、类型genre等细节可随时扩展这也印证了文档「存储 title、duration、language」的需求点。Show包含id、Movie、Screen、LocalDateTime startTime以及一个重要的PricingStrategy定价策略字段见 Show.java。每个场次独立绑定定价策略为「工作日/周末不同票价」的需求预留了扩展位。Seat拥有id、row、col、typeSeatTypeREGULAR / PREMIUM与可变状态statusSeatStatusAVAILABLE / LOCKED / BOOKED见 Seat.java。座位初始状态统一为AVAILABLE。User构造时自动生成UUID作为用户 IDUser.java无需手动指定。Booking不可变预订实体包含user、show、seats、totalAmount、payment其唯一构造方式是通过内部静态类BookingBuilderBuilder 模式并对外提供confirmBooking()将所选座位批量置为BOOKEDBooking.java。Cinema / Screen / City / Payment影院域被建模为 城市 → 影院 → 影厅 的层级关系Payment记录支付金额、状态与交易号TXN。状态枚举定义在 enums 目录SeatStatusAVAILABLE / LOCKED / BOOKED、SeatTypeREGULAR / PREMIUM、PaymentStatusSUCCESS / FAILURE。其中SeatStatus.LOCKED是并发座位锁机制的核心状态详见第四节。三、系统门面MovieBookingServiceSingleton 双重检查锁定文档中MovieTicketBookingSystem是整个系统的聚合点源码将其实现为单例门面MovieBookingService见 MovieBookingService.java。public class MovieBookingService { private static volatile MovieBookingService instance; private final MapString, City cities; private final MapString, Cinema cinemas; private final MapString, Movie movies; private final MapString, User users; private final MapString, Show shows; private final SeatLockManager seatLockManager; private final BookingManager bookingManager; private MovieBookingService() { /* 初始化各 ConcurrentHashMap 与核心服务 */ } public static MovieBookingService getInstance() { if (instance null) { synchronized (MovieBookingService.class) { if (instance null) { instance new MovieBookingService(); } } } return instance; } // ... }关键设计点双重检查锁定Double-Checked Locking单例volatile修饰实例 synchronized同步块 二次判空兼顾线程安全与性能避免每次调用getInstance()都加锁。并发容器所有实体注册表使用ConcurrentHashMapMovieBookingService.java与单例一起构成多线程安全的基础设施。核心服务组合SeatLockManager座位锁与BookingManager预订管理器由系统在构造时创建并持有职责分离。门面提供的数据管理方法与文档对应关系文档方法源码实现方法说明addMovie()addMovie(Movie movie)注册电影对象addTheater()addCinema(id, name, cityId, screens)影院需绑定城市与影厅列表addShow()addShow(id, movie, screen, startTime, pricingStrategy)场次必须绑定定价策略bookTicket()bookTickets(userId, showId, desiredSeats, paymentStrategy)返回OptionalBookinggetAvailableShows()findShows(movieTitle, cityName)按「电影名 城市」过滤场次值得注意文档示例中的addShow(movie, theater, showTime)在真实实现中演进为需要显式指定Screen与PricingStrategy的签名MovieBookingService.java——因为Show的构造依赖这两个对象这体现了从「概念模型」到「可运行实现」的必经细化过程。四、预订流程核心BookingManager 与 SeatLockManager 的并发座位锁这是本系统最有价值的实现细节也是面试中高频考察的并发控制场景多个用户同时抢同一场次的座位如何保证不超卖4.1 预订五步流水线BookingManager.createBooking() 定义了标准的预订流水线public OptionalBooking createBooking(User user, Show show, ListSeat seats, PaymentStrategy paymentStrategy) { // 1. 锁定座位 seatLockManager.lockSeats(show, seats, user.getId()); // 2. 计算总价调用该场次的定价策略 double totalAmount show.getPricingStrategy().calculatePrice(seats); // 3. 处理支付 Payment payment paymentStrategy.pay(totalAmount); // 4. 支付成功 → 用 Builder 构建预订对象 if (payment.getStatus() PaymentStatus.SUCCESS) { Booking booking new Booking.BookingBuilder() .setUser(user).setShow(show).setSeats(seats) .setTotalAmount(totalAmount).setPayment(payment) .build(); // 5. 确认预订座位置为 BOOKED并释放锁 booking.confirmBooking(); seatLockManager.unlockSeats(show, seats, user.getId()); return Optional.of(booking); } else { System.out.println(Payment failed. Please try again.); return Optional.empty(); // 支付失败 → 无预订 } }整个流程是教科书式的「锁座位 → 计价 → 支付 → 确认 → 释放锁」失败路径通过Optional.empty()表达避免了文档中预想的异常抛出对调用方的强制侵入。4.2 座位锁管理器超时自动释放 防竞态SeatLockManager.java 是实现「座位临时锁定」的关键组件其设计要点双层 ConcurrentHashMap 记录锁归属MapShow, MapSeat, String外层按场次分组内层记录「座位 → 锁定用户 ID」SeatLockManager.java。以 Show 为粒度做 synchronized 同步锁定前先synchronized (show)保证同一场次内的座位操作原子性SeatLockManager.java。可重入校验遍历请求座位任一座位状态非AVAILABLE即拒绝整批锁定SeatLockManager.java防止「部分成功」导致的数据不一致。定时自动解锁锁定后通过ScheduledExecutorService调度一个LOCK_TIMEOUT_MS当前示例为 500ms真实系统通常为分钟级后的解锁任务SeatLockManager.java模拟「用户选座后长时间未支付座位自动释放」的行业惯例。防竞态解锁解锁时仅当锁记录仍归属同一用户才移除并根据座位当前状态区分「超时释放」LOCKED → AVAILABLE与「预订完成释放」BOOKED 保留锁记录移除SeatLockManager.java。优雅停机shutdown()方法关闭调度线程池并等待任务结束避免定时器泄漏SeatLockManager.java。这套机制完整覆盖了「瞬时并发抢座」与「超时释放」两个真实场景是面试中讲解「如何避免座位超卖」的最佳代码论据。五、设计模式落地分析原文档列出的四种设计模式在源码中均有对应实现此外还额外使用了 Builder 模式模式文档说明源码落点具体位置Singleton预订系统单例实例双重检查锁定单例MovieBookingService.javaFactory创建不同类型的座位实体对象由Screen.addSeat()直接构造Seat(id, row, col, type)工厂逻辑收敛于枚举SeatType的getPrice()MovieBookingDemo.java、SeatTypeObserver座位可用性/电影发布通知Movie继承MovieSubject维护观察者列表并提供notifyObservers()UserObserver订阅电影发布事件MovieSubject.java、UserObserverStrategy不同定价策略定价WeekdayPricingStrategy/WeekendPricingStrategy实现PricingStrategy.calculatePrice(seats)支付CreditCardPaymentStrategy实现PaymentStrategy.pay(amount)strategy/pricing、strategy/paymentBuilder额外—Booking.BookingBuilder分步组装不可变预订对象Booking.java以定价策略为例WeekdayPricingStrategy直接汇总所选座位的SeatType.getPrice()WeekdayPricingStrategy.java而Show在创建时即可注入任意策略实现新增「会员价」「早鸟价」无需改动预订流水线——这正是 Strategy 模式「开闭原则」的直接体现。支付侧同样可插拔Demo 中传入的CreditCardPaymentStrategy模拟了支付网关交互约 95% 成功率CreditCardPaymentStrategy.java换用其他支付方式只需新增一个实现类。六、异常与失败处理策略原文档规划了四类异常SeatNotAvailableException、InvalidShowException、BookingFailedException、CancellationFailedException。从当前源码实现看失败路径主要采用以下两种更轻量的方式表达这是文档规划与工程实践之间的合理差异可以理解为演进方向座位不可用SeatLockManager在锁定阶段打印Seat X is not available.并直接返回不产生预订SeatLockManager.java预订/支付失败createBooking返回Optional.empty()由调用方通过isPresent()判断成功与否BookingManager.java。文档规划的异常体系可作为下一步演进目标在Optional无法表达错误原因时升级为带语义的领域异常同时BookingBuilder.build()中的注释也预留了「校验逻辑可在此添加」的扩展位Booking.java。七、完整演示与运行方式仓库提供了开箱即用的演示程序 MovieBookingDemo.java完整模拟了 Alice 的购票旅程系统初始化注册纽约、洛杉矶两座城市添加《The Matrix》120 分钟与《Avengers: Endgame》170 分钟两部电影。构建影厅座位创建Screen(S1)A/B 两排各 10 个座位前 5 列为REGULAR、后 5 列为PREMIUMMovieBookingDemo.java。排片为两部电影各安排一场 2 小时/5 小时后开场的场次均注入WeekdayPricingStrategy。观察者演示Alice 以UserObserver订阅《Avengers: Endgame》调用avengers.notifyObservers()模拟「电影定档通知」。搜索场次service.findShows(Avengers: Endgame, New York)按片名 城市过滤。查看并选择座位过滤AVAILABLE座位后Alice 选中其中两个座位。支付并预订bookTickets(alice.getId(), show.getId(), desiredSeats, new CreditCardPaymentStrategy(1234-5678-9876-5432, 123))。结果核验打印预订 ID、用户、电影、座位、总金额与支付状态并逐一输出所选座位的最终状态应全部为BOOKED。系统关闭调用service.shutdown()释放定时调度线程资源。运行方式Java 环境cd solutions/java/src javac movieticketbookingsystem/MovieBookingDemo.java java movieticketbookingsystem.MovieBookingDemo运行后会依次看到观察者通知、座位锁定日志Locked seats: [...] for user ...、支付处理、预订成功信息与座位状态核验输出是验证整套并发锁与预订流水线最直接的手段。八、框架扩展方向原文档末尾给出了 6 个扩展方向结合现有架构可以这样落地接入支付网关Add payment processing已有PaymentStrategy抽象只需新增真实网关实现类替换CreditCardPaymentStrategy的模拟逻辑。座位选择 UIAdd seat selection UISeatLockManager提供的「锁定 超时释放」天然支撑交互式选座页面用户选座期间座位保持 LOCKED。分级定价Add pricing tiers在SeatType已区分 REGULAR / PREMIUM 的基础上扩展PricingStrategy实现如WeekendPricingStrategy、会员价。高级排片算法Add show schedulingMovieBookingService.addShow()目前由调用方指定时间可在此处增加冲突检测与黄金时段排片逻辑。通知系统Add notification system复用现成的MovieSubject/UserObserver观察者基础设施扩展预订确认、开场提醒等通知类型。用户评价Add user reviewsUser实体目前仅含id/name/email可平滑增加评价集合字段Movie侧同样可扩展评分聚合逻辑。九、总结从 README.md 的需求骨架出发本系统在 Java 中完成了从概念模型到可运行代码的完整落地City → Cinema → Screen三级影院建模、SeatStatus状态机驱动的座位管理、SeatLockManager的并发锁 超时释放机制、BookingManager的五步预订流水线以及 Singleton / Builder / Observer / Strategy 四种模式的协同应用。这套设计覆盖了「需求分析 → 实体建模 → 并发控制 → 模式落地 → 可运行 Demo」的完整 LLD 链路既可作为面试手写系统设计的参考范本也可以作为继续扩展支付、选座 UI 与通知系统的起点。相关类图见仓库根目录的 class-diagrams/movieticketbookingsystem-class-diagram.png源码均可直接阅读与运行验证。赞分享示例工程【免费下载链接】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点击查看免费下载相关推荐电影票预订系统Movie Ticket Booking SystemC 低层设计实战类建模、座位锁定与并发安全电影票预订系统Movie Ticket Booking SystemC 低层设计实战类建模、座位锁定与并发安全 本文基于 awesome low le示例工程Movie Ticket Booking SystemBookMyShow 式低层设计全解析需求拆解、类图建模与并发座位预订实战Movie Ticket Booking SystemBookMyShow 式低层设计全解析需求拆解、类图建模与并发座位预订实战 本文以开源仓库 awes示例工程发布-订阅Pub-Sub系统低层设计LLD实战从需求到并发安全的 Java/Go 多语言实现发布 订阅Pub Sub系统低层设计LLD实战从需求到并发安全的 Java/Go 多语言实现 导读 本文以 problems/pub sub syst示例工程上一篇Super IO插件Blender剪贴板导入导出终极解决方案3倍提升3D工作流效率下一篇LeRobot训练可视化全攻略从指标监控到行为分析的完整解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进