In this design, we incorporate the Strategy Pattern as part of the seat assignment logic so that different seat assignment algorithms can be swapped in without affecting the rest of the system. The design also employs other design patterns (Singleton, Factory, and DAO/Repository ideas) and addresses key points:
Entities and Relationships:
Major entities include Flight, Seat, Passenger, and Booking. A Flight has many seats and bookings. A Booking links a Passenger to a Flight with a specific Seat.
Flight Scheduling, Booking, and Cancellations:
The FlightScheduler (Singleton) manages flight scheduling and cancellations. The BookingManager (Singleton and Factory) creates bookings and handles cancellations.
Seat Assignment:
The system uses a SeatAssignmentStrategy interface (Strategy Pattern) with a default implementation that assigns the first available seat based on the requested seat class. This makes it easy to swap in alternate assignment algorithms (for example, window or aisle preference) if needed.
Passenger Information:
Passenger details are stored in the Passenger entity and linked to each Booking.
Below is the detailed Java code with inline comments that explain the design patterns used:
import java.time.LocalDateTime;
import java.util.*;
// --------------------- ENUMS ---------------------
// Enum representing different seat classes.
enum SeatClass {
ECONOMY,
BUSINESS,
FIRST
}
// Enum representing booking status.
enum BookingStatus {
BOOKED,
CANCELLED
}
// --------------------- ENTITIES ---------------------
// Seat entity represents a seat on a flight.
class Seat {
private String seatNumber;
private SeatClass seatClass;
private boolean isAvailable;
public Seat(String seatNumber, SeatClass seatClass) {
this.seatNumber = seatNumber;
this.seatClass = seatClass;
this.isAvailable = true;
}
public String getSeatNumber() {
return seatNumber;
}
public SeatClass getSeatClass() {
return seatClass;
}
public boolean isAvailable() {
return isAvailable;
}
// Mark the seat as booked.
public void bookSeat() {
this.isAvailable = false;
}
// Release the seat when a booking is cancelled.
public void releaseSeat() {
this.isAvailable = true;
}
}
// Flight entity represents a scheduled flight with seats and bookings.
class Flight {
private String flightId;
private String flightNumber;
private String origin;
private String destination;
private LocalDateTime departureTime;
private LocalDateTime arrivalTime;
private List<Seat> seats; // All seats available on the flight.
private List<Booking> bookings; // Bookings for the flight.
public Flight(String flightId, String flightNumber, String origin, String destination,
LocalDateTime departureTime, LocalDateTime arrivalTime, List<Seat> seats) {
this.flightId = flightId;
this.flightNumber = flightNumber;
this.origin = origin;
this.destination = destination;
this.departureTime = departureTime;
this.arrivalTime = arrivalTime;
this.seats = seats;
this.bookings = new ArrayList<>();
}
public String getFlightId() {
return flightId;
}
public String getFlightNumber() {
return flightNumber;
}
public String getOrigin() {
return origin;
}
public String getDestination() {
return destination;
}
public LocalDateTime getDepartureTime() {
return departureTime;
}
public LocalDateTime getArrivalTime() {
return arrivalTime;
}
public List<Seat> getSeats() {
return seats;
}
public List<Booking> getBookings() {
return bookings;
}
// Add a booking to this flight.
public void addBooking(Booking booking) {
bookings.add(booking);
}
}
// Passenger entity represents a customer.
class Passenger {
private String passengerId;
private String name;
private String email;
private String phone;
public Passenger(String passengerId, String name, String email, String phone) {
this.passengerId = passengerId;
this.name = name;
this.email = email;
this.phone = phone;
}
public String getPassengerId() {
return passengerId;
}
public String getName() {
return name;
}
// Additional getters (email, phone) can be added as needed.
}
// Booking entity links a passenger to a flight and assigns a seat.
class Booking {
private String bookingId;
private Flight flight;
private Passenger passenger;
private Seat seat;
private BookingStatus status;
public Booking(String bookingId, Flight flight, Passenger passenger, Seat seat) {
this.bookingId = bookingId;
this.flight = flight;
this.passenger = passenger;
this.seat = seat;
this.status = BookingStatus.BOOKED;
}
public String getBookingId() {
return bookingId;
}
public Flight getFlight() {
return flight;
}
public Passenger getPassenger() {
return passenger;
}
public Seat getSeat() {
return seat;
}
public BookingStatus getStatus() {
return status;
}
// Cancel the booking and release the seat.
public void cancelBooking() {
if (status == BookingStatus.BOOKED) {
status = BookingStatus.CANCELLED;
seat.releaseSeat();
}
}
}
// --------------------- STRATEGY PATTERN FOR SEAT ASSIGNMENT ---------------------
/*
* Strategy Pattern: SeatAssignmentStrategy defines an interface for different seat assignment algorithms.
* This allows the BookingManager to use different strategies (e.g., first available, window preference, etc.) without changing its code.
*/
interface SeatAssignmentStrategy {
Seat assignSeat(Flight flight, SeatClass seatClass);
}
// Default strategy: assign the first available seat in the requested class.
class FirstAvailableSeatAssignmentStrategy implements SeatAssignmentStrategy {
@Override
public Seat assignSeat(Flight flight, SeatClass seatClass) {
for (Seat seat : flight.getSeats()) {
if (seat.getSeatClass() == seatClass && seat.isAvailable()) {
return seat;
}
}
return null;
}
}
// --------------------- FLIGHT SCHEDULER ---------------------
/*
* Singleton Pattern: FlightScheduler ensures only one instance manages flight scheduling.
*/
class FlightScheduler {
private static FlightScheduler instance;
private List<Flight> flights;
// Private constructor to enforce Singleton.
private FlightScheduler() {
flights = new ArrayList<>();
}
public static synchronized FlightScheduler getInstance() {
if (instance == null) {
instance = new FlightScheduler();
}
return instance;
}
// Schedule a new flight.
public void scheduleFlight(Flight flight) {
flights.add(flight);
}
// Retrieve a flight by its ID.
public Flight getFlightById(String flightId) {
for (Flight flight : flights) {
if (flight.getFlightId().equals(flightId)) {
return flight;
}
}
return null;
}
public List<Flight> getAllFlights() {
return flights;
}
// Cancel a flight and all its associated bookings.
public void cancelFlight(String flightId) {
Flight flight = getFlightById(flightId);
if (flight != null) {
// Cancel each booking on the flight.
for (Booking booking : flight.getBookings()) {
booking.cancelBooking();
// (Observer Pattern could be applied here to notify passengers.)
}
flights.remove(flight);
}
}
}
// --------------------- BOOKING MANAGER ---------------------
/*
* Singleton & Factory Pattern: BookingManager is responsible for creating Booking objects.
* It uses a SeatAssignmentStrategy (Strategy Pattern) to determine which seat to assign.
*/
class BookingManager {
private static BookingManager instance;
// The strategy to assign seats; default is FirstAvailableSeatAssignmentStrategy.
private SeatAssignmentStrategy seatAssignmentStrategy = new FirstAvailableSeatAssignmentStrategy();
// Private constructor for Singleton.
private BookingManager() { }
public static synchronized BookingManager getInstance() {
if (instance == null) {
instance = new BookingManager();
}
return instance;
}
// Optionally allow the strategy to be changed.
public void setSeatAssignmentStrategy(SeatAssignmentStrategy strategy) {
this.seatAssignmentStrategy = strategy;
}
// Create a booking for a passenger on a flight with the desired seat class.
public Booking createBooking(Flight flight, Passenger passenger, SeatClass seatClass) {
// Use the Strategy Pattern to assign a seat.
Seat availableSeat = seatAssignmentStrategy.assignSeat(flight, seatClass);
if (availableSeat == null) {
System.out.println("No available seats for " + seatClass);
return null;
}
// Book the seat.
availableSeat.bookSeat();
// Generate a booking ID and create the booking (Factory Pattern).
String bookingId = UUID.randomUUID().toString();
Booking booking = new Booking(bookingId, flight, passenger, availableSeat);
flight.addBooking(booking);
return booking;
}
// Cancel an existing booking.
public void cancelBooking(Booking booking) {
booking.cancelBooking();
// Additional processing (e.g., refunds, notifications) can be added here.
}
}
// --------------------- MAIN APPLICATION ---------------------
public class AirlineReservationSystemApp {
public static void main(String[] args) {
// 1. Flight Scheduling
// Get the FlightScheduler singleton instance.
FlightScheduler flightScheduler = FlightScheduler.getInstance();
// Create a list of seats for the flight.
List<Seat> seats = new ArrayList<>();
seats.add(new Seat("1A", SeatClass.FIRST));
seats.add(new Seat("1B", SeatClass.FIRST));
seats.add(new Seat("5A", SeatClass.BUSINESS));
seats.add(new Seat("5B", SeatClass.BUSINESS));
seats.add(new Seat("10A", SeatClass.ECONOMY));
seats.add(new Seat("10B", SeatClass.ECONOMY));
seats.add(new Seat("10C", SeatClass.ECONOMY));
seats.add(new Seat("10D", SeatClass.ECONOMY));
// Create a Flight with schedule details.
Flight flight = new Flight(
"FL123", "AI-202", "New York", "London",
LocalDateTime.of(2025, 5, 20, 10, 30),
LocalDateTime.of(2025, 5, 20, 22, 30),
seats
);
// Schedule the flight.
flightScheduler.scheduleFlight(flight);
// 2. Booking and Seat Assignment
// Create Passenger objects.
Passenger passenger1 = new Passenger("P001", "Alice Smith", "alice@example.com", "1234567890");
Passenger passenger2 = new Passenger("P002", "Bob Johnson", "bob@example.com", "0987654321");
// Get the BookingManager singleton instance.
BookingManager bookingManager = BookingManager.getInstance();
// Create bookings with seat assignment based on the seat class.
Booking booking1 = bookingManager.createBooking(flight, passenger1, SeatClass.ECONOMY);
if (booking1 != null) {
System.out.println("Booking successful: " + booking1.getBookingId() + " assigned seat " + booking1.getSeat().getSeatNumber());
}
Booking booking2 = bookingManager.createBooking(flight, passenger2, SeatClass.FIRST);
if (booking2 != null) {
System.out.println("Booking successful: " + booking2.getBookingId() + " assigned seat " + booking2.getSeat().getSeatNumber());
}
// 3. Cancellation
// Cancel a booking example.
System.out.println("Cancelling booking: " + booking1.getBookingId());
bookingManager.cancelBooking(booking1);
System.out.println("Booking status: " + booking1.getStatus());
// Flight scheduling, booking, cancellations, and seat assignments are demonstrated.
}
}
Explanation of Key Points & Design Patterns
Entities and Relationships:
Flight, Seat, Passenger, Booking:
These classes represent the core entities. A Flight contains a list of Seats and Bookings. A Booking links a Passenger to a Flight and a Seat.
Flight Scheduling, Booking, and Cancellations:
FlightScheduler (Singleton Pattern):
Ensures a single instance is responsible for scheduling flights and processing cancellations.
BookingManager (Singleton & Factory Pattern):
Centralizes the creation of Booking objects. It uses a Strategy Pattern for seat assignment.
Seat Assignment:
SeatAssignmentStrategy (Strategy Pattern):
An interface that defines how a seat should be assigned.
FirstAvailableSeatAssignmentStrategy:
The default strategy, which assigns the first available seat matching the requested class.
This makes it easy to plug in different strategies in the future (for example, preferences for window or aisle seats).
Passenger Information:
Passenger:
Stores essential customer details and is linked to bookings.
Conclusion
This LLD for an Airline Reservation System demonstrates:
How to model key entities and their relationships.
How to manage flight scheduling, booking, and cancellations using Singleton managers.
How to implement seat assignment with a flexible Strategy Pattern.
How passenger information is maintained and linked to bookings.
This modular and extensible design employs multiple design patterns to ensure the system is maintainable, scalable, and adaptable to new requirements—a robust blueprint for a technical interview discussion.