Bird
Raised Fist0

Airline Reservation System

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
๐ŸŽฏ
Airline Reservation System - Seats, Classes, Waitlist, Cancellation
40 min ยท medium
medium

Design a system for an airline with 5 seat classes (Economy, Premium Economy, Business, First, and Charter), 4 boarding gates, and a dynamic pricing structure. The system must handle seat booking, waitlisting when classes are full, and notify waitlisted customers on cancellations. It should support concurrent bookings and cancellations without data races.

  • Each Flight has multiple Seat objects categorized by SeatClass enum.
  • Booking allocation strategy varies per SeatClass (e.g., strict first-come-first-served vs. priority).
  • Waitlist must be notified immediately when a seat is freed by cancellation.
  • Seats can be booked, cancelled, or waitlisted concurrently by multiple threads.
  • Pricing depends on SeatClass and dynamic factors (not detailed here).
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define Seat and SeatClass with Factory Pattern
Design the Seat class hierarchy and SeatClass enum. Implement a factory method in Flight to create seats per SeatClass.
๐Ÿ’ก Hint
Use enum for SeatClass to ensure type safety and exhaustive switch. Use abstract class Seat to hold shared state like seatNumber and isAvailable.
abstract class Seat(seatNumber, volatile boolean isAvailable) - abstract because it holds shared instance state; interface cannot hold fields in Java. SeatClass as enum ensures compile-time safety and exhaustive switch.
Mid: Recognizes Factory pattern for seat creation. Senior: Explains why volatile is needed on isAvailable to ensure visibility across threads booking concurrently.
โš ๏ธCommon Wrong Answer
Using String for seat class leads to runtime typo bugs and no exhaustive switch checking; using interface for Seat prevents holding shared state like isAvailable.
Step 2
Implement Booking with Strategy Pattern per SeatClass
Design Booking allocation strategies that differ by SeatClass. How will you apply the Strategy pattern to encapsulate these behaviors?
๐Ÿ’ก Hint
Define BookingStrategy interface with allocateSeat(Flight, SeatClass). Concrete strategies implement different allocation logic. Flight holds a Map<SeatClass, BookingStrategy>.
interface BookingStrategy { Seat allocateSeat(Flight f, SeatClass c); } - interface used here because no shared state is needed, only behavior. Flight uses composition to hold strategies per SeatClass.
Mid: Identifies Strategy pattern for allocation. Senior: Explains how composition allows extending strategies without modifying Flight (Open-Closed Principle).
โš ๏ธCommon Wrong Answer
Hardcoding allocation logic inside Flight violates Single Responsibility and Open-Closed principles, making extension error-prone.
Step 3
Design Waitlist with Observer Pattern and Thread Safety
How will you design the Waitlist to be notified on seat cancellations? Ensure thread safety when notifying multiple waitlisted customers.
๐Ÿ’ก Hint
Use Observer pattern: Waitlist observes Flight or Seat. Use synchronized blocks or concurrent collections to manage waitlist safely.
Waitlist implements Observer interface; Flight extends Observable. Use synchronized methods on waitlist add/remove and notify to prevent race conditions. Use CopyOnWriteArrayList for observers to avoid ConcurrentModificationException.
Mid: Names Observer pattern. Senior: Traces thread interleaving where Thread 1 cancels seat and notifies waitlist while Thread 2 adds to waitlist, requiring synchronization to avoid lost notifications.
โš ๏ธCommon Wrong Answer
Not synchronizing waitlist updates leads to lost notifications or ConcurrentModificationException during iteration.
Step 4
Handle Cancellation and Notify Waitlist Atomically
Implement cancellation logic that frees a seat and notifies the waitlist atomically to avoid race conditions.
๐Ÿ’ก Hint
Use synchronized boolean cancelBooking(Booking b) in Flight to atomically set seat availability and notify waitlist.
synchronized boolean cancelBooking(Booking b) - atomic check-and-set of seat availability and immediate notification to waitlist prevents race conditions where multiple threads see seat as available simultaneously.
Mid: Uses synchronized method for cancellation. Senior: Explains exact thread interleaving where without synchronization two threads cancel same seat causing inconsistent state or double notification.
โš ๏ธCommon Wrong Answer
Using separate unsynchronized steps for seat freeing and notification causes race conditions and inconsistent waitlist state.
Step 5
Model Flight and Seat Relationships with Lifecycle Ownership
Define the relationships between Flight, Seat, Booking, and Waitlist. Specify lifecycle ownership and composition vs aggregation.
๐Ÿ’ก Hint
Flight composes Seat objects (Seats cannot exist without Flight). Booking associates with Seat and Flight. Waitlist aggregates customers independently.
Flight composition Seat: Flight creates and owns Seat lifecycle; Seat cannot exist independently. Booking association with Seat and Flight: Booking references but does not own Seat. Waitlist aggregation: Waitlist holds references to customers who exist independently.
Mid: Correctly identifies composition vs aggregation. Senior: Explains lifecycle implications for garbage collection and design extensibility.
โš ๏ธCommon Wrong Answer
Modeling Seat as aggregation leads to dangling seats without Flight context; modeling Booking as composition of Seat leads to tight coupling and lifecycle confusion.
๐Ÿ”Œ
API Design Challenge
Design RESTful APIs for booking seats, managing waitlists, and handling cancellations that ensure consistency and concurrency safety.
  • Use idempotent POST requests for booking to handle retries safely.
  • Design WebSocket or Server-Sent Events endpoints for real-time waitlist notifications.
  • Consider optimistic locking or versioning to prevent lost updates during concurrent cancellations.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • Use enum SeatClass for type safety
  • abstract class Seat with volatile isAvailable field
  • Factory pattern for seat creation in Flight
  • Strategy pattern for booking allocation per SeatClass
  • Observer pattern for waitlist notification
  • synchronized cancellation method for atomic seat freeing and notification
Good to Have - 30%
  • Thread-safe waitlist using CopyOnWriteArrayList
  • Clear lifecycle ownership: Flight composes Seat
  • Booking associates with Seat and Flight without ownership
  • Use of volatile and synchronized to prevent race conditions
Bonus - 10%
  • Dynamic pri
โœ…
Model Answer
โ–ผ Reveal

    • Use enum SeatClass for compile-time safety and exhaustive switch statements.
    • abstract class Seat holds shared instance state like volatile boolean isAvailable to ensure visibility across threads.
    • Factory pattern in Flight creates Seat instances per SeatClass, encapsulating creation logic.
    • Strategy pattern encapsulates booking allocation logic per SeatClass, allowing extension without modifying Flight (Open-Closed Principle).
    • Observer pattern connects Waitlist to Flight/Seat for immediate notification on cancellations.
    • Use synchronized methods and volatile fields to prevent race conditions during booking and cancellation.
    • Flight composes Seat objects, enforcing lifecycle ownership; Booking associates with Seat and Flight without ownership.
    • Waitlist uses thread-safe collections (e.g., CopyOnWriteArrayList) and synchronized methods to manage concurrent access.
    • Cancellation method is synchronized to atomically free seat and notify waitlist, preventing inconsistent states.
    • Avoid using String for types to prevent runtime bugs; prefer enums and interfaces/abstract classes for behavior and state separation.

    Practice

    (1/5)
    1. In the Restaurant Management System, should the MenuItem be designed as an abstract class or an interface? Consider that MenuItem has shared state like price and description, and behavior like calculateDiscount().
    easy
    A. Interface, because it allows multiple inheritance and enforces method signatures without state.
    B. Abstract class, because it can hold shared state and provide default behavior implementations.
    C. Interface, because Java 8+ interfaces can have default methods and fields for state.
    D. Abstract class, because it forces subclasses to implement all methods explicitly.

    Solution

    1. Step 1: Analyze state and behavior requirements

      MenuItem has shared state (price, description) and behavior (calculateDiscount), which interfaces cannot hold as fields.
    2. Step 2: Abstract class supports shared state and default behavior

      Abstract classes can have instance variables and method implementations, making them suitable for MenuItem.
    3. Final Answer:

      Option B -> Option B
    4. Quick Check:

      Shared state + behavior -> abstract class [check]
    Hint: Stateful base class -> abstract class, stateless contract -> interface [check]
    Common Mistakes:
    2. In designing the vending machine's product selection module, should Product be modeled as an abstract class or an interface? Consider that products have shared state like price and inventory count, but different behaviors like dispense() and getDescription().
    easy
    A. Abstract class, because it allows sharing common state and default behavior implementations among products.
    B. Abstract class, because it enforces immutability of product instances.
    C. Interface, because Java interfaces can now have default methods to share code and state.
    D. Interface, because all products only share behavior signatures without any shared state.

    Solution

    1. Step 1: Analyze shared state and behavior

      Products share common state like price and inventory count, which requires fields and possibly default implementations.
    2. Step 2: Choose between interface and abstract class

      Abstract classes can hold state and provide default method implementations, while interfaces cannot hold instance state (only constants).
    3. Final Answer:

      Option A -> Option A
    4. Quick Check:

      Abstract class supports shared state and behavior [check]
    Hint: Abstract class holds state; interface only behavior signatures [check]
    Common Mistakes:
    3. A class has a private constructor and a static synchronized getInstance() method returning a single instance. Which pattern is applied and why is this the CORRECT use case?
    easy
    A. Factory Method pattern, because it controls object creation with a static method.
    B. Prototype pattern, to clone existing instances instead of creating new ones.
    C. Builder pattern, to construct complex objects step-by-step.
    D. Singleton pattern, ensuring only one instance exists and is thread-safe.

    Solution

    1. Step 1: Identify the pattern from constructor and method

      The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single shared instance with thread safety.
    2. Step 2: Eliminate other creational patterns

      Factory Method creates objects but doesn't enforce single instance; Builder constructs complex objects but not singleton; Prototype clones instances, not restricts to one.
    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      Private constructor + synchronized static getter -> Singleton pattern [check]
    Hint: Private constructor + static synchronized getter -> Singleton [check]
    Common Mistakes:
    4. You want to add a WeekendBonusRule that gives players extra moves on weekends without modifying existing classes. Which SOLID principle guides the minimal change, and what is the correct approach?
    medium
    A. Single Responsibility Principle: add weekend logic inside the Player class.
    B. Open/Closed Principle: create a new class implementing a MoveRule interface and inject it into the game engine.
    C. Liskov Substitution Principle: subclass Player to WeekendPlayer with bonus logic.
    D. Dependency Inversion Principle: make Player depend on concrete WeekendBonusRule.

    Solution

    1. Step 1: Identify SOLID principle for extension without modification

      Open/Closed Principle (OCP) states software entities should be open for extension but closed for modification.
    2. Step 2: Evaluate approaches

      Subclassing Player to WeekendPlayer allows extension without modifying Player; injecting new MoveRule class also respects OCP but requires interface design.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      Subclassing extends behavior without modifying base class [check]
    Hint: Extend via subclass or interface, don't modify existing classes [check]
    Common Mistakes:
    5. The vending machine currently applies a flat pricing strategy. To add a WeekendFeeStrategy that charges extra on weekends, which minimal change respects SOLID principles?
    medium
    A. Create a new WeekendFeeStrategy class implementing PricingStrategy and inject it without modifying existing classes.
    B. Modify the existing PricingStrategy class to add weekend fee logic inside its calculatePrice() method.
    C. Add a boolean isWeekend flag to Product and adjust price accordingly.
    D. Add conditional logic for weekend fees in the vending machine's dispense() method.

    Solution

    1. Step 1: Identify the SOLID principle involved

      The Open-Closed Principle (OCP) requires classes to be open for extension but closed for modification.
    2. Step 2: Evaluate options against OCP

      Create a new WeekendFeeStrategy class implementing PricingStrategy and inject it without modifying existing classes. adds a new strategy class without modifying existing code, respecting OCP. Others modify existing classes or mix concerns.
    3. Final Answer:

      Option A -> Option A
    4. Quick Check:

      New strategy class extends pricing without modifying existing code [check]
    Hint: OCP: extend pricing via new class, don't modify existing [check]
    Common Mistakes:
    Recommended

    Ready to prove it?

    Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

    10 questions~5 mineasy hard