- 示例工程
【免费下载链接】awesome-low-level-design
Learn Low Level Design (LLD) and prepare for interviews using free resources.
本篇文章以 solutions/java/src/airlinemanagementsystem/README.md 为骨架,结合仓库内完整的 Java 源码,系统讲解航空管理系统(Airline Management System)的低层设计(LLD)思路:从问题陈述、需求分析到核心实体识别、类设计、UML 建模,再到可运行的示例代码与扩展方向。读者学完后,将能够独立搭建一个涵盖航班、飞机、座位、乘客、预订与支付六大模块的航空业务系统,并理解其背后单例、状态机等设计模式的落地方式。
问题陈述与需求分析
问题陈述
Design and implement an Airline Management System that allows users to book flights, manage passengers, handle seat assignments, process payments, and track bookings and flights.
即:设计并实现一个航空管理系统,支持用户预订航班、管理乘客、处理座位分配、处理支付,并跟踪预订与航班状态。这是面试中经典的领域建模题目,考察的是对真实业务实体、实体关系与业务状态流转的抽象能力。
需求要点
原文档明确列出了七条核心需求,它们是整个类设计的输入:
| 需求 | 说明 |
|---|---|
| 航班管理 | 每个航班拥有唯一航班号、关联飞机、出发地、目的地与时刻表 |
| 飞机管理 | 每架飞机有型号(model)与一组座位(seats) |
| 座位管理 | 系统为每个航班管理座位分配与可用性 |
| 乘客管理 | 乘客可被新增、更新,并与预订关联 |
| 预订管理 | 用户可预订航班,系统跟踪预订、已分配座位与乘客 |
| 支付处理 | 系统为预订处理支付 |
| 可扩展性 | 易于扩展忠诚度计划、餐食选择、多航段旅程等新特性 |
面向对象设计原则的体现
从源码结构看,本实现遵循了几个典型的 LLD 原则:
- 单一职责:
Flight只关注航班本身,Seat只负责座位状态,BookingManager独立管理预订生命周期; - 封装:座位状态、预订状态均通过方法(
reserve()/release()/cancel())改变,外部不能直接改写; - 领域包划分:源码按业务域组织为
flight/、seat/、booking/、payment/四个子包,外加根包下的Aircraft、Passenger、AirlineManagementSystem,职责边界清晰。
核心实体设计
原文档给出了七大核心实体,它们在仓库源码中均有对应类:
| 实体 | 所在路径 | 职责 |
|---|---|---|
AirlineManagementSystem | AirlineManagementSystem.java | 门面入口,统一管理航班、乘客、预订与支付 |
Flight | flight/Flight.java | 航班,含航班号、飞机、起降地、时刻与座位 |
Aircraft | Aircraft.java | 飞机,含尾号、型号与总座位数 |
Seat | seat/Seat.java | 座位,含座位号、舱位类型与可用状态 |
Passenger | Passenger.java | 乘客,含 ID、姓名与邮箱 |
Booking | booking/Booking.java | 预订,关联乘客、航班、座位与价格 |
Payment | payment/Payment.java | 支付交易,含支付 ID、方式、金额与状态 |
实体关系
从源码可以确认实体之间的聚合与关联关系:
Flight聚合Aircraft,并持有Map<String, Seat>座位表与List<Seat> availableSeats可用座位缓存;Aircraft在构造时按totalSeats建立座位集合(见 Aircraft.java 构造逻辑);Booking关联一个Flight、一个Passenger、一个Seat;Payment独立于Booking,由PaymentProcessor统一处理。
类设计详解
1. AirlineManagementSystem(门面类)
原文档描述的字段为List<Flight> flights, List<Booking> bookings, List<Passenger> passengers, PaymentProcessor paymentProcessor。仓库实现进一步演进为以 Map 为主、以服务类为辅的架构:
private final Map<String, Flight> flights; private final Map<String, Aircraft> aircrafts; private final Map<String, Passenger> passengers; private final FlightSearch flightSearch; private final BookingManager bookingManager; private final PaymentProcessor paymentProcessor;关键方法(与 AirlineManagementSystem.java 对应):
| 方法 | 作用 |
|---|---|
addPassenger(name, email) | 创建乘客并登记,返回乘客对象 |
addAircraft(tailNumber, model, totalSeats) | 以尾号登记飞机 |
addFlight(source, destination, departure, arrival, aircraftNumber) | 创建航班并加入搜索索引 |
searchFlights(source, destination, date) | 委托FlightSearch按条件检索 |
bookFlight(flightNumber, passengerId, seat, price) | 委托BookingManager创建预订 |
cancelBooking(bookingNumber) | 委托BookingManager取消预订 |
processPayment(payment) | 委托PaymentProcessor处理支付 |
值得注意的是:bookFlight返回类型为Booking(可空),调用方需判空;而原文档示例中的bookFlight(Passenger, Flight, Seat, Payment)签名在仓库中演化为按 ID 引用,这样更贴近真实系统的解耦风格。
2. Flight(航班)
源码中Flight的字段为:
private final String flightNumber; // UUID 生成,保证唯一 private final String source; private final String destination; private final LocalDateTime departureTime; private final LocalDateTime arrivalTime; private final FlightStatus status; // ON_TIME / DELAYED / CANCELLED private final Aircraft aircraft; private final Map<String, Seat> seats; private final List<Seat> availableSeats;与文档字段(String flightNumber, Aircraft aircraft, String source, String destination, Date schedule, List<Seat> seats)相比,仓库实现将时间细化为了departureTime与arrivalTime两个LocalDateTime,并新增了FlightStatus状态机,便于后续支持延误、取消等真实场景。
座位管理的关键是并发安全:isSeatAvailable、reserveSeat、releaseSeat全部以synchronized修饰(见 flight/Flight.java),防止同一座位被并发重复预订。
3. Aircraft(飞机)
private final String tailNumber; // 机尾编号,作为唯一标识 private final String model; // 如 Boeing 747、Airbus A380 private final int totalSeats; // 总座位数注意:文档中Aircraft描述为"model + seats",仓库实现则以tailNumber作为注册键,totalSeats决定座位数量,见 Aircraft.java。
4. Seat(座位)
private final String seatNumber; private final SeatType type; // ECONOMY / PREMIUM_ECONOMY / BUSINESS / FIRST_CLASS private SeatStatus status; // AVAILABLE / RESERVED / OCCUPIED(见 SeatStatus)reserve()将状态置为RESERVED;release()将状态置回AVAILABLE;isBooked()用synchronized保证读安全,判断是否为OCCUPIED(见 seat/Seat.java)。
5. Passenger(乘客)
字段为id(UUID)、name、email。与文档的int id, String name, String contactInfo相比,仓库实现将 ID 改为 UUID 字符串,联系方式收敛为email,更贴合现代系统。
6. Booking(预订)
private final String id; private final Flight flight; private final Passenger passenger; private final Seat seat; private final double price; private BookingStatus status; // CONFIRMED / CANCELLED / PENDING / EXPIREDcancel()方法在将状态置为CANCELLED的同时调用seat.release()释放座位(见 booking/Booking.java),体现了座位资源与预订状态的一致性维护——这是预订系统的关键设计点。
7. Payment 与 PaymentProcessor(支付)
public class Payment { private final String paymentId; private final String paymentMethod; // 如 CREDIT_CARD private final double amount; private PaymentStatus status; // PENDING / COMPLETED ... }Payment.processPayment()完成支付逻辑并将状态置为COMPLETED(见 payment/Payment.java);PaymentProcessor以单例模式封装处理入口(见 payment/PaymentProcessor.java)。
8. BookingManager 与 PaymentProcessor:单例模式落地
仓库中BookingManager与PaymentProcessor均采用双重用途的单例模式——getInstance()方法加synchronized,私有构造函数确保全局唯一:
public static synchronized BookingManager getInstance() { if (instance == null) { instance = new BookingManager(); } return instance; }预订创建与取消操作在synchronized(lock)块内执行(见 booking/BookingManager.java),避免并发下 Map 数据竞争。
UML 类图
仓库根目录提供了与本主题强相关的类图:
该图直观展示了AirlineManagementSystem与Flight、Aircraft、Passenger、Booking、Payment等实体之间的聚合与关联关系,可作为面试讲解时的辅助图示。
示例用法与 Demo
原文档示例代码
原文档给出了最简演示流程:
AirlineManagementSystem system = new AirlineManagementSystem(); Aircraft aircraft = new Aircraft("Boeing 737", seatList); Flight flight = new Flight("AI101", aircraft, "DEL", "BOM", new Date(), seatList); system.addFlight(flight); Passenger alice = new Passenger(1, "Alice", "alice@email.com"); system.addPassenger(alice); Seat seat = flight.getAvailableSeats().get(0); Payment payment = new Payment(1, 5000.0, "CREDIT_CARD"); system.bookFlight(alice, flight, seat, payment);仓库真实 Demo 流程
仓库中的 AirlineManagementSystemDemo.java 展示了更贴近实际 API 的完整调用链,对应五个步骤:
- 创建乘客:
addPassenger("John Doe", "john@example.com"); - 注册飞机:
addAircraft("A001", "Boeing 747", 300)(300 座); - 创建航班:
addFlight("New York", "London", departureTime, arrivalTime, "A001"),时刻用LocalDateTime.now().plusDays(1)模拟次日起飞; - 搜索航班:
searchFlights("New York", "London", LocalDate.now().plusDays(1)); - 预订与取消:
bookFlight(flight1.getFlightNumber(), passenger1.getId(), new Seat("25A", SeatType.ECONOMY), 100),随后cancelBooking(booking.getId())释放座位。
其中FlightSearch.searchFlights使用流式过滤完成三条件匹配(出发地、目的地、日期,见 flight/FlightSearch.java),是理解搜索链路的关键实现。
可运行性说明
本实现基于 Java 8+(使用java.timeAPI),无第三方依赖,可直接编译运行:进入 solutions/java/src 目录,将airlinemanagementsystem包加入 classpath 后执行AirlineManagementSystemDemo即可看到搜索、预订、取消的完整输出。这是仓库所有 LLD 题目的统一 Java 组织方式,便于面试前快速演示。
扩展方向:框架的可扩展性
原文档最后给出了三个扩展方向,结合源码可给出具体落点:
- 忠诚度计划(Loyalty Program):可在
Passenger上增加积分字段,或在Payment完成后增加积分回写钩子,不侵入现有Booking核心链路; - 餐食选择(Meal Selection):为
Booking增加可选的mealPreference属性,或在BookingManager.createBooking中增加可选参数重载; - 多航段旅程(Multi-leg Journey):将
Booking与Flight的一对一关系演进为Booking持有List<Flight>,同时让Flight支持中转衔接字段。
从源码结构看,AirlineManagementSystem已把所有业务委托给FlightSearch、BookingManager、PaymentProcessor三个独立服务,新增上述功能只需替换或扩展对应服务,无需改动门面调用方——这正是本设计预留的扩展点。
小结
通过本文可以掌握一条完整的 LLD 落地链路:需求分析 → 实体识别 → 类设计 → 状态建模 → 门面服务分层 → 并发安全 → 可运行 Demo → 扩展预留。仓库中该题的完整源码位于 solutions/java/src/airlinemanagementsystem,配合 class-diagrams/airlinemanagementsystem-class-diagram.png 类图,可作为面试复习的高质量参照;同一仓库还提供了 C++、C#、Go 等语言的对应实现,便于横向对比各语言的领域建模风格。
- 示例工程
【免费下载链接】awesome-low-level-design
Learn Low Level Design (LLD) and prepare for interviews using free resources.
相关推荐
用 Go 设计航空管理系统:基于 awesome-low-level-design 的 LLD 实战与单例并发实现解析
用 Go 设计航空管理系统:基于 awesome low level design 的 LLD 实战与单例并发实现解析 导读 本篇技术指南以开源仓库 aweso
示例工程设计外卖配送系统(Food Delivery Service):基于 awesome-low-level-design 的完整 LLD 实战解析
设计外卖配送系统(Food Delivery Service):基于 awesome low level design 的完整 LLD 实战解析 导读 本文以
示例工程在线拍卖系统低层设计(LLD)实战:基于 awesome-low-level-design 的 C++ 实现全解析
在线拍卖系统低层设计(LLD)实战:基于 awesome low level design 的 C++ 实现全解析 本篇技术指南以 awesome low le
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考