酒店管理系统(Hotel Management System)低层设计实战:基于 awesome-low-level-design 的 C++ 全流程实现解析

原创2026-09-30 22:33:161,829 阅读
文章标签:示例工程教程后端

酒店管理系统(Hotel Management System)低层设计实战:基于 awesome-low-level-design 的 C++ 全流程实现解析

导读

本文以 solutions/cpp/hotelmanagementsystem 目录下的完整 C++ 实现为主线,深入拆解酒店管理系统的低层设计(LLD)全流程:从需求分析、领域建模(Guest / Room / Booking / HotelManager)到预订、入住、退房、取消预订的完整状态机流转。读完本文,你将掌握如何用 C++ 面向对象设计实现一个可扩展的酒店预订核心系统,并学会把这份实现直接复用到 LLD 面试的代码与架构讲解中。

一、系统需求分析(Requirements)

原设计文档给出了 8 条核心需求,它们是整个类设计与状态机设计的依据:

  1. 预订、入住、退房:系统应允许客人预订房间、办理入住(check-in)与退房(check-out)。
  2. 多房型管理:支持单人间、双人间、豪华房、套房等不同类型房间(当前 C++ 实现收敛为 STANDARD / DELUXE / SUITE 三档)。
  3. 可用性与预订状态管理:系统必须跟踪房间可用性和预订状态。
  4. 前台运营管理:允许酒店员工管理客人信息、房间分配与账单结算。
  5. 多支付方式:支持现金、信用卡、在线支付等多种支付方式(在类设计中体现为 Payment 接口及其具体实现类)。
  6. 并发预订与数据一致性:需要处理并发预订并保证数据一致性。
  7. 报表与分析:为酒店管理提供报表与统计能力(本实现通过 displayAvailableRooms、displayBookingHistory、displayAllGuests、displayAllBookings 等查询接口落地)。
  8. 可扩展性:系统应能支撑大量房间与客人的扩展。

需求 1~4 是本实现完全覆盖的核心业务闭环;需求 5~8 属于可演进方向,其中 6~8 在设计上通过集中式的 HotelManager 门面式入口为后续加锁、持久化、报表模块预留了扩展点。

二、核心类、接口与枚举设计

设计文档给出了 9 个核心构件,全部在仓库源码中落地:

构件 源码文件 职责
Guest Guest.hpp 客人实体,含 ID、姓名、邮箱、电话、地址
Room Room.hpp 房间实体,含房号、类型、价格、容量、状态
RoomType Room.hpp 房型枚举:STANDARD / DELUXE / SUITE
RoomStatus Room.hpp 房间状态:AVAILABLE / OCCUPIED / UNDER_MAINTENANCE
Booking Booking.hpp 预订记录,含客人、房间、入住/退房日期、金额、状态
BookingStatus Booking.hpp 预订状态:CONFIRMED / CHECKED_IN / CHECKED_OUT / CANCELLED
Payment(接口,文档层设计) 设计文档定义 定义处理支付的契约,由 CashPayment、CreditCardPayment 等实现
HotelManager(即文档中的 HotelManagementSystem) HotelManager.hpp 中央控制器,统一管理房间、客人、预订,处理预订/入住/退房/取消
HotelDemo(对应 HotelManagementSystemDemo) HotelDemo.cpp 演示完整业务流程

关于 Singleton 的说明:设计文档描述 HotelManagementSystem 采用单例模式,而本仓库的 C++ 实现以 HotelManager 类承担该角色(构造后由 main 持有一个实例),未使用 static 单例。这种"文档给出目标设计、代码给出可编译落地版本"的组合,恰好展示了 LLD 面试中"先画类图、再落代码"的常见路径。

2.1 Guest:客人信息载体

Guest.hpp 定义的 Guest 封装了 5 个字段:guestId、name、email、phone、address,并提供全 getter 与 displayInfo()。实现见 Guest.cpp,构造时一次性传入全部信息:

Guest(std::string guestId, std::string name, std::string email,
      std::string phone, std::string address);

在演示代码中,一个典型客人实例为 new Guest("G001", "John Doe", "john@example.com", "+1-555-0123", "123 Main St")。

2.2 Room:房间实体与状态

Room.hpp 中 Room 聚合了房型、状态、价格、容量四个关键属性:

enum class RoomType { STANDARD, DELUXE, SUITE };
enum class RoomStatus { AVAILABLE, OCCUPIED, UNDER_MAINTENANCE };

class Room {
private:
    std::string roomNumber;
    RoomType type;
    RoomStatus status;
    double pricePerNight;
    int capacity;
public:
    Room(std::string roomNumber, RoomType type, double pricePerNight, int capacity);
    // getters...
    void setStatus(RoomStatus status);
    void displayInfo() const;
};

关键细节(见 Room.cpp):

  • 新房间构造时默认 status = RoomStatus::AVAILABLE,保证初始可用性一致;
  • setStatus 是房间状态变更的唯一入口,由 HotelManager 在入住/退房/取消时驱动;
  • displayInfo() 会输出房号、类型、状态、每晚价格(两位小数)、容量。

演示数据:Room("101", STANDARD, 100.0, 2)、Room("201", DELUXE, 150.0, 3)、Room("301", SUITE, 250.0, 4)。

2.3 Booking:预订聚合根

Booking.hpp 中 Booking 通过指针关联 Guest 与 Room,构成预订的完整上下文:

class Booking {
private:
    std::string bookingId;
    Guest* guest;
    Room* room;
    std::string checkInDate;
    std::string checkOutDate;
    int numberOfNights;
    double totalAmount;
    BookingStatus status;
public:
    Booking(...);
    void calculateTotalAmount();
    void setStatus(BookingStatus status);
    void displayInfo() const;
};

Booking.cpp 中的两个要点:

  • 构造即计价:构造函数中 status 初始化为 CONFIRMED,并立即调用 calculateTotalAmount(),金额 = room->getPricePerNight() * numberOfNights;
  • 状态机:BookingStatus 的四个取值 CONFIRMED → CHECKED_IN → CHECKED_OUT / CANCELLED 定义了预订的完整生命周期(详见第三节)。

三、HotelManager:中央控制器与业务状态机

HotelManager.hpp 是系统的门面(Facade 式入口),内部维护三组容器和一个 ID 自增器:

std::vector<Room*> rooms;
std::vector<Guest*> guests;
std::vector<Booking*> bookings;
int bookingIdCounter; // 初始为 1,生成 "BK1"、"BK2" ...

3.1 预订流程(createBooking)

HotelManager.cpp 中 createBooking 的校验与装配逻辑:

Booking* HotelManager::createBooking(std::string guestId, std::string roomNumber,
                                     std::string checkInDate, std::string checkOutDate,
                                     int numberOfNights) {
    Guest* guest = findGuest(guestId);
    Room* room = findRoom(roomNumber);
    if (!guest || !room || room->getStatus() != RoomStatus::AVAILABLE) {
        return nullptr;
    }
    Booking* booking = new Booking(generateBookingId(), guest, room,
                                   checkInDate, checkOutDate, numberOfNights);
    bookings.push_back(booking);
    return booking;
}

三个失败条件缺一不可:客人不存在、房间不存在、房间不可用。注意:本实现预订时不立即占用房间,房间状态仅在 check-in 时变更为 OCCUPIED;因此"可用性约束"发生在 check-in 而非 createBooking,这是该实现的明确取舍(真实系统中通常会在 createBooking 时就把房间标记为 BOOKED,以应对并发预订——这一点正是需求 6 指出的演进点)。

3.2 入住 / 退房 / 取消的状态机

三个核心操作构成严格的状态迁移矩阵:

操作 前置状态(Booking) 后置状态(Booking) 房间状态变化
checkIn CONFIRMED CHECKED_IN AVAILABLE → OCCUPIED
checkOut CHECKED_IN CHECKED_OUT OCCUPIED → AVAILABLE
cancelBooking CONFIRMED CANCELLED (本实现房间始终 AVAILABLE,见上)

对应实现(HotelManager.cpp):

bool HotelManager::checkIn(std::string bookingId) {
    Booking* booking = findBooking(bookingId);
    if (!booking || booking->getStatus() != BookingStatus::CONFIRMED) return false;
    booking->setStatus(BookingStatus::CHECKED_IN);
    booking->getRoom()->setStatus(RoomStatus::OCCUPIED);
    return true;
}

bool HotelManager::checkOut(std::string bookingId) {
    Booking* booking = findBooking(bookingId);
    if (!booking || booking->getStatus() != BookingStatus::CHECKED_IN) return false;
    booking->setStatus(BookingStatus::CHECKED_OUT);
    booking->getRoom()->setStatus(RoomStatus::AVAILABLE);
    return true;
}

bool HotelManager::cancelBooking(std::string bookingId) {
    Booking* booking = findBooking(bookingId);
    if (!booking || booking->getStatus() != BookingStatus::CONFIRMED) return false;
    booking->setStatus(BookingStatus::CANCELLED);
    booking->getRoom()->setStatus(RoomStatus::AVAILABLE);
    return true;
}

可以推断的设计意图:所有业务操作都要求"目标预订存在且处于允许的前置状态",非法迁移一律返回 false,从而保证数据一致性;findRoom / findGuest / findBooking 三个私有查找函数把"容器遍历 + 按 ID/房号匹配"的逻辑集中复用。

3.3 查询与报表能力

HotelManager.cpp 提供了 4 个查询接口,对应需求 7 的报表与分析:

  • displayAvailableRooms():遍历房间,仅打印 AVAILABLE 的房间;
  • displayBookingHistory(guestId):按客人 ID 过滤其全部预订记录;
  • displayAllGuests() / displayAllBookings():全量列表,用于前台运营管理。

此外 HotelManager.cpp 的析构函数统一 delete 所有 rooms / guests / bookings 指针,避免内存泄漏,是面试中值得强调的资源管理细节。

四、完整业务闭环:HotelDemo 演示走查

HotelDemo.cpp 串起了整个流程,可对照以下顺序运行理解:

  1. 创建 HotelManager 实例;
  2. 添加 3 间房(101 标准间 / 201 豪华间 / 301 套房);
  3. 添加 1 位客人 G001(John Doe);
  4. displayAvailableRooms() 打印初始可用房间;
  5. createBooking("G001", "101", "2024-01-01", "2024-01-03", 2) 创建 2 晚预订,成功后打印预订详情(含自动计算的 $200.00 总额);
  6. checkIn(bookingId) 后再次 displayAvailableRooms(),可看到 101 房已从列表消失(状态变为 OCCUPIED);
  7. checkOut(bookingId) 释放房间;
  8. displayBookingHistory("G001") 查看该客人的预订历史,此时状态为 Checked Out。

编译运行方式(在 solutions/cpp/hotelmanagementsystem/ 目录下):

g++ -std=c++17 HotelDemo.cpp HotelManager.cpp Booking.cpp Room.cpp Guest.cpp -o hotel_demo
./hotel_demo

五、类图与面试要点

仓库的 hotelmanagementsystem-class-diagram.png 提供了该系统的完整类图,直观呈现了 Guest、Room、Booking、HotelManager(HotelManagementSystem)之间的关联关系,非常适合面试讲解与博客配图使用。

酒店管理系统类图

面试与复习时可抓住以下要点:

  • 关系建模:Booking 聚合 Guest 与 Room(指针关联),HotelManager 组合管理三类容器,是典型的"实体 + 门面控制器"分层;
  • 状态机设计:BookingStatus 四态与 RoomStatus 三态的双状态机联动是本题的考核核心,务必能画出状态迁移表(见 3.2 节);
  • 枚举即约束:RoomType、RoomStatus、BookingStatus 全部使用 enum class,编译期类型安全;
  • 演进空间:需求 5(多支付方式)在文档层通过 Payment 接口 + 具体实现类(CashPayment、CreditCardPayment 等)设计;需求 6(并发一致性)在本实现中体现为集中的 HotelManager 业务入口,可在该处引入互斥锁或数据库事务;需求 8(可扩展性)则依赖当前清晰的容器式数据结构。

从源码结构看,本实现有意保持"单文件、无外部依赖、可直接编译运行"的教学形态,非常适合作为 LLD 面试前的快速复习模板——先读懂状态机,再动手重写一遍 HotelManager 的四个核心操作,即可达到面试手写要求。

登录后查看全文
awesome-low-level-design