problemunknownood

OOD - Airline Management System

Updated: Dec 31, 2025

Problem

Design an object-oriented system for managing airline operations including flight scheduling, aircraft management, crew assignments, ticket reservations, and passenger services. The system must handle complex workflows such as multi-leg itineraries, seat assignments, real-time flight status updates, and payment processing. Your design should demonstrate SOLID principles and incorporate design patterns to ensure scalability and maintainability as the airline expands its fleet and route network.

Solution

1. Requirements Analysis

Functional Requirements:

  • Manage airline fleet including aircraft models, configurations, and maintenance schedules
  • Support multiple airports with location-specific operations and gate assignments
  • Schedule flights with recurring patterns (daily, weekly) and custom one-time schedules
  • Enable passenger search for flights by origin, destination, date, and preferences
  • Process ticket reservations for single and multi-leg itineraries
  • Assign seats to passengers based on availability, class, and special requirements
  • Track flight instances with real-time status updates (scheduled, boarding, departed, in-air, landed, delayed, cancelled)
  • Manage crew assignments (pilots, flight attendants) to flight instances with qualification checking
  • Handle payments with multiple methods and generate invoices
  • Support check-in process both online and at airport kiosks
  • Send automated notifications for booking confirmations, flight updates, gate changes, and delays
  • Generate reports on flight utilization, revenue, on-time performance

Non-Functional Requirements:

  • Extensibility: New aircraft types, seat classes, and pricing strategies should be addable without modifying core logic (Open/Closed Principle)
  • Reliability: Flight status updates must propagate to all affected reservations immediately
  • Scalability: Support thousands of concurrent flight searches and bookings
  • Data Integrity: Prevent double-booking of seats and ensure accurate inventory management
  • Performance: Search results should return within 3 seconds for queries spanning 6 months

2. Use Case Diagram

Actors:

  • Customer: Searches flights, books tickets, manages reservations, checks in online
  • Front Desk Agent: Assists with bookings, handles check-ins, processes special requests
  • Admin: Manages aircraft, schedules flights, sets pricing, handles cancellations
  • Crew Member (Pilot/Attendant): Views assigned flights and schedules
  • System: Sends notifications, updates flight statuses, processes automated check-ins

Primary Use Cases:

  • Search Flights - Find available flights matching travel criteria
  • Book Reservation - Reserve seats for one or more passengers
  • Select Seats - Choose specific seats based on preferences
  • Process Payment - Handle ticket payment and issue confirmation
  • Check-In - Complete check-in and obtain boarding pass
  • Manage Flight Schedule - Add/modify/cancel flight schedules
  • Assign Crew - Allocate pilots and crew to flight instances
  • Update Flight Status - Track real-time flight progress
  • Cancel Reservation - Process cancellation with refund calculation
graph TD
    subgraph AirlineSystem["Airline Management System"]
        UC1[Search Flights]
        UC2[Book Reservation]
        UC3[Select Seats]
        UC4[Process Payment]
        UC5[Check-In]
        UC6[Manage Flight Schedule]
        UC7[Assign Crew]
        UC8[Update Flight Status]
        UC9[Cancel Reservation]
        UC10[Send Notifications]
    end

    Customer[πŸ‘€ Customer]
    Agent[πŸ‘” Front Desk Agent]
    Admin[πŸ‘¨β€πŸ’Ό Admin]
    Crew[✈️ Crew Member]
    System[πŸ–₯️ System]

    Customer --> UC1
    Customer --> UC2
    Customer --> UC3
    Customer --> UC5
    Customer --> UC9

    Agent --> UC2
    Agent --> UC3
    Agent --> UC5

    Admin --> UC6
    Admin --> UC7
    Admin --> UC8

    Crew --> UC1

    System --> UC8
    System --> UC10

    UC2 -.includes.-> UC4
    UC5 -.includes.-> UC10
    UC8 -.includes.-> UC10

    style Customer fill:#E3F2FD,stroke:#1976D2,stroke-width:2px
    style Agent fill:#FFF3E0,stroke:#F57C00,stroke-width:2px
    style Admin fill:#F3E5F5,stroke:#7B1FA2,stroke-width:2px
    style Crew fill:#E0F2F1,stroke:#00796B,stroke-width:2px
    style System fill:#E8F5E9,stroke:#388E3C,stroke-width:2px

    style UC1 fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style UC2 fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style UC3 fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style UC5 fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style UC9 fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style UC4 fill:#FFE082,stroke:#F57F17,stroke-width:2px
    style UC6 fill:#E1BEE7,stroke:#6A1B9A,stroke-width:2px
    style UC7 fill:#E1BEE7,stroke:#6A1B9A,stroke-width:2px
    style UC8 fill:#B2DFDB,stroke:#00796B,stroke-width:2px
    style UC10 fill:#C8E6C9,stroke:#2E7D32,stroke-width:2px

3. Class Diagram

Core Classes and Their Responsibilities:

Aircraft & Airport Management:

  • Aircraft - Represents physical aircraft with model, registration, seat configuration
  • SeatConfiguration - Defines seat layout for different aircraft types
  • Airport - Airport entity with code, name, location, terminal information
  • Gate - Boarding gate assignments

Flight Scheduling (Strategy Pattern):

  • Flight - Master flight route (e.g., AA101 from JFK to LAX)
  • FlightSchedule (interface) - Strategy for generating flight instances
  • RecurringSchedule - Daily/weekly recurring flights
  • CustomSchedule - One-time special flights
  • FlightInstance - Specific occurrence of a flight with date, time, aircraft, crew

Reservation Management:

  • Reservation - Booking entity with passengers, seats, payment
  • Itinerary - Collection of reservations forming a complete trip
  • Passenger - Individual traveler with personal details
  • Seat - Physical seat with class, type, and features
  • SeatAssignment - Links passenger to specific seat on flight instance

Crew Management:

  • CrewMember (abstract) - Base for all crew
  • Pilot, FlightAttendant - Specific crew types
  • CrewAssignment - Assigns crew to flight instance with role validation

Payment & Notification:

  • Payment - Handles payment processing
  • PricingStrategy (interface) - Dynamic pricing based on demand, season, etc.
  • NotificationService - Observer pattern for alerts

Repositories (Repository Pattern):

  • FlightRepository - Flight data access
  • ReservationRepository - Reservation persistence
  • AircraftRepository - Aircraft inventory
classDiagram
    %% Aircraft and Airport
    class Aircraft {
        -String registrationNumber
        -String model
        -String manufacturer
        -int yearBuilt
        -SeatConfiguration seatConfig
        -AircraftStatus status
        +getTotalSeats() int
        +getAvailableSeats(FlightInstance) List~Seat~
    }

    class SeatConfiguration {
        -Map~SeatClass int~ seatCounts
        -List~Seat~ seats
        +getSeatsForClass(SeatClass) List~Seat~
    }

    class Seat {
        -String seatNumber
        -SeatClass seatClass
        -SeatType seatType
        -bool hasExtraLegroom
        -bool isWindowSeat
        +isAvailable(FlightInstance) bool
    }

    class Airport {
        -String code
        -String name
        -String city
        -String country
        -List~Gate~ gates
        +getAvailableGate(DateTime) Gate
    }

    class Gate {
        -String gateNumber
        -String terminal
        +isAvailable(DateTime) bool
    }

    %% Flight Scheduling with Strategy Pattern
    class Flight {
        -String flightNumber
        -Airport origin
        -Airport destination
        -Duration duration
        -List~FlightSchedule~ schedules
        +createInstances(DateRange) List~FlightInstance~
    }

    class FlightSchedule {
        <<interface>>
        +generateInstances(DateRange) List~FlightInstance~
    }

    class RecurringSchedule {
        -List~DayOfWeek~ daysOfWeek
        -Time departureTime
        +generateInstances(DateRange) List~FlightInstance~
    }

    class CustomSchedule {
        -Date specificDate
        -Time departureTime
        +generateInstances(DateRange) List~FlightInstance~
    }

    class FlightInstance {
        -String instanceId
        -Flight flight
        -DateTime departureTime
        -DateTime arrivalTime
        -Aircraft aircraft
        -Gate departureGate
        -Gate arrivalGate
        -FlightStatus status
        -List~CrewAssignment~ crew
        +updateStatus(FlightStatus)
        +assignCrew(CrewMember, CrewRole)
        +getAvailableSeats() List~Seat~
    }

    FlightSchedule <|.. RecurringSchedule
    FlightSchedule <|.. CustomSchedule
    Flight --> FlightSchedule
    Flight --> Airport
    FlightInstance --> Flight
    FlightInstance --> Aircraft
    FlightInstance --> Gate
    Aircraft --> SeatConfiguration
    SeatConfiguration --> Seat
    Airport --> Gate

    %% Reservations
    class Reservation {
        -String confirmationNumber
        -Customer customer
        -FlightInstance flightInstance
        -List~SeatAssignment~ seatAssignments
        -ReservationStatus status
        -Money totalCost
        -DateTime bookingTime
        +confirmReservation()
        +cancel() Money
        +checkIn()
    }

    class Itinerary {
        -String itineraryId
        -Customer customer
        -List~Reservation~ reservations
        -Money totalPrice
        +addReservation(Reservation)
        +calculateTotalCost() Money
    }

    class SeatAssignment {
        -Passenger passenger
        -Seat seat
        -FlightInstance flightInstance
        -bool isCheckedIn
        +checkIn()
    }

    class Passenger {
        -String passportNumber
        -String firstName
        -String lastName
        -Date dateOfBirth
        -String nationality
        +getFullName() String
    }

    class Customer {
        -String customerId
        -String email
        -String phone
        -FrequentFlyerAccount loyaltyAccount
        -List~Itinerary~ travelHistory
        +createItinerary() Itinerary
        +getLoyaltyDiscount() decimal
    }

    Itinerary --> Reservation
    Reservation --> Customer
    Reservation --> FlightInstance
    Reservation --> SeatAssignment
    SeatAssignment --> Passenger
    SeatAssignment --> Seat
    Customer --> Itinerary

    %% Crew Management
    class CrewMember {
        <<abstract>>
        -String employeeId
        -String name
        -List~String~ certifications
        +isQualifiedFor(Aircraft) bool*
    }

    class Pilot {
        -String licenseNumber
        -int totalFlightHours
        -List~String~ aircraftQualifications
        +isQualifiedFor(Aircraft) bool
    }

    class FlightAttendant {
        -String attendantId
        -List~String~ languages
        +isQualifiedFor(Aircraft) bool
    }

    class CrewAssignment {
        -CrewMember crewMember
        -FlightInstance flightInstance
        -CrewRole role
        +validate() bool
    }

    CrewMember <|-- Pilot
    CrewMember <|-- FlightAttendant
    CrewAssignment --> CrewMember
    CrewAssignment --> FlightInstance

    %% Pricing Strategy Pattern
    class PricingStrategy {
        <<interface>>
        +calculatePrice(Reservation) Money
    }

    class BasePricing {
        -Map~SeatClass Money~ baseRates
        +calculatePrice(Reservation) Money
    }

    class DemandPricing {
        -PricingStrategy basePricing
        +calculatePrice(Reservation) Money
        -getOccupancyRate(FlightInstance) decimal
    }

    class SeasonalPricing {
        -PricingStrategy basePricing
        -Map~Season decimal~ multipliers
        +calculatePrice(Reservation) Money
    }

    PricingStrategy <|.. BasePricing
    PricingStrategy <|.. DemandPricing
    PricingStrategy <|.. SeasonalPricing
    DemandPricing --> PricingStrategy
    SeasonalPricing --> PricingStrategy

    %% Payment
    class Payment {
        -String transactionId
        -Money amount
        -PaymentMethod method
        -PaymentStatus status
        -DateTime timestamp
        +process() bool
        +refund(Money) bool
    }

    Reservation --> Payment

    %% Repositories
    class FlightRepository {
        <<interface>>
        +searchFlights(SearchCriteria) List~FlightInstance~
        +findById(String) FlightInstance
        +save(FlightInstance)
    }

    class ReservationRepository {
        <<interface>>
        +findByConfirmation(String) Reservation
        +findByCustomer(String) List~Reservation~
        +save(Reservation)
    }

Design Patterns Applied:

  1. Strategy Pattern: FlightSchedule allows different scheduling algorithms (recurring vs custom)
  2. Strategy Pattern: PricingStrategy enables dynamic pricing based on various factors
  3. Repository Pattern: Abstracts data access for flights and reservations
  4. Observer Pattern: NotificationService notifies customers of flight changes
  5. Factory Pattern: (Implied) Creating different crew member types
  6. Template Method: CrewMember.isQualifiedFor() abstract method

SOLID Principles Demonstrated:

  • Single Responsibility: Each class has one clear purpose (Flight handles routes, FlightInstance handles specific occurrences)
  • Open/Closed: New schedule types can be added without modifying Flight class
  • Liskov Substitution: Any FlightSchedule or CrewMember subclass can replace parent
  • Interface Segregation: Focused repository interfaces
  • Dependency Inversion: Services depend on repository interfaces, not concrete implementations

4. Activity Diagrams

Activity: Booking a Flight Reservation

flowchart TD
    Start([πŸ‘€ Customer searches flights]) --> EnterCriteria[πŸ“ Enter origin, destination, dates]
    EnterCriteria --> Search[πŸ” Search available flights]
    Search --> Results{βœ… Flights found?}
    Results -->|No| NoResults[❌ Show no results message]
    NoResults --> End1([End])
    Results -->|Yes| SelectFlight[✈️ Select flight]
    SelectFlight --> MultiLeg{πŸ”„ Add connecting flight?}
    MultiLeg -->|Yes| Search
    MultiLeg -->|No| EnterPassengers[πŸ‘₯ Enter passenger details]
    EnterPassengers --> SelectSeats[πŸ’Ί Select seats]
    SelectSeats --> ReviewBooking[πŸ“‹ Review booking summary]
    ReviewBooking --> CalculatePrice[πŸ’° Calculate total price]
    CalculatePrice --> Confirm{πŸ€” Confirm booking?}
    Confirm -->|No| End1
    Confirm -->|Yes| ProcessPayment[πŸ’³ Process payment]
    ProcessPayment --> PaymentOK{βœ“ Payment successful?}
    PaymentOK -->|No| PaymentFail[⚠️ Show payment error]
    PaymentFail --> ProcessPayment
    PaymentOK -->|Yes| CreateReservation[πŸ“ Create reservation]
    CreateReservation --> AssignSeats[πŸ’Ί Assign seats to passengers]
    AssignSeats --> GenerateConfirmation[🎫 Generate confirmation]
    GenerateConfirmation --> SendEmail[πŸ“§ Send confirmation email]
    SendEmail --> End2([βœ… Booking complete])

    style Start fill:#E1F5FE,stroke:#01579B,stroke-width:3px
    style End1 fill:#FFCDD2,stroke:#C62828,stroke-width:3px
    style End2 fill:#C8E6C9,stroke:#2E7D32,stroke-width:3px

    style Search fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style SelectFlight fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style EnterPassengers fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style SelectSeats fill:#81D4FA,stroke:#0277BD,stroke-width:2px
    style ReviewBooking fill:#81D4FA,stroke:#0277BD,stroke-width:2px

    style CalculatePrice fill:#FFE082,stroke:#F57F17,stroke-width:2px
    style ProcessPayment fill:#FFE082,stroke:#F57F17,stroke-width:2px
    style PaymentFail fill:#FFAB91,stroke:#D84315,stroke-width:2px

    style CreateReservation fill:#A5D6A7,stroke:#388E3C,stroke-width:2px
    style AssignSeats fill:#A5D6A7,stroke:#388E3C,stroke-width:2px
    style GenerateConfirmation fill:#81C784,stroke:#2E7D32,stroke-width:2px
    style SendEmail fill:#81C784,stroke:#2E7D32,stroke-width:2px

    style Results fill:#FFF9C4,stroke:#F9A825,stroke-width:2px
    style MultiLeg fill:#FFF9C4,stroke:#F9A825,stroke-width:2px
    style Confirm fill:#FFF9C4,stroke:#F9A825,stroke-width:2px
    style PaymentOK fill:#FFF9C4,stroke:#F9A825,stroke-width:2px

    style EnterCriteria fill:#E1BEE7,stroke:#7B1FA2,stroke-width:2px
    style NoResults fill:#FFCCBC,stroke:#E64A19,stroke-width:2px

Activity: Online Check-In Process

flowchart TD
    Start([πŸ‘€ Passenger initiates check-in]) --> EnterConfirmation[πŸ”’ Enter confirmation number]
    EnterConfirmation --> RetrieveReservation[πŸ“‹ Retrieve reservation]
    RetrieveReservation --> ValidReservation{βœ“ Valid reservation?}
    ValidReservation -->|No| Error([❌ Invalid reservation])
    ValidReservation -->|Yes| CheckTiming{⏰ Within check-in window?}
    CheckTiming -->|No| TooEarly[⏰ Check-in not open yet]
    TooEarly --> End1([End])
    CheckTiming -->|Yes| ShowPassengers[πŸ‘₯ Display passenger list]
    ShowPassengers --> SelectPassenger[πŸ‘€ Select passenger]
    SelectPassenger --> HasSeat{πŸ’Ί Seat already assigned?}
    HasSeat -->|No| ShowSeatMap[πŸ—ΊοΈ Display seat map]
    ShowSeatMap --> SelectSeat[πŸ’Ί Select seat]
    SelectSeat --> ConfirmSeat{βœ“ Confirm seat selection?}
    ConfirmSeat -->|No| ShowSeatMap
    ConfirmSeat -->|Yes| AssignSeat[βœ… Assign seat]
    HasSeat -->|Yes| AssignSeat
    AssignSeat --> MorePassengers{πŸ‘₯ More passengers?}
    MorePassengers -->|Yes| SelectPassenger
    MorePassengers -->|No| VerifyPassport[πŸ›‚ Verify travel documents]
    VerifyPassport --> AcceptTerms[πŸ“„ Accept baggage terms]
    AcceptTerms --> GenerateBoardingPass[🎫 Generate boarding pass]
    GenerateBoardingPass --> SendBoardingPass[πŸ“§ Email/SMS boarding pass]
    SendBoardingPass --> MarkCheckedIn[βœ… Mark as checked in]
    MarkCheckedIn --> End2([βœ… Check-in complete])

    style Start fill:#FFF3E0,stroke:#E65100,stroke-width:3px
    style End1 fill:#FFCDD2,stroke:#C62828,stroke-width:3px
    style End2 fill:#C8E6C9,stroke:#2E7D32,stroke-width:3px
    style Error fill:#FFCDD2,stroke:#C62828,stroke-width:3px

    style EnterConfirmation fill:#FFE0B2,stroke:#EF6C00,stroke-width:2px
    style RetrieveReservation fill:#FFE0B2,stroke:#EF6C00,stroke-width:2px
    style ShowPassengers fill:#FFCC80,stroke:#F57C00,stroke-width:2px
    style SelectPassenger fill:#FFCC80,stroke:#F57C00,stroke-width:2px

    style ShowSeatMap fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style SelectSeat fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style AssignSeat fill:#81D4FA,stroke:#0277BD,stroke-width:2px

    style VerifyPassport fill:#CE93D8,stroke:#7B1FA2,stroke-width:2px
    style AcceptTerms fill:#CE93D8,stroke:#7B1FA2,stroke-width:2px

    style GenerateBoardingPass fill:#AED581,stroke:#689F38,stroke-width:2px
    style SendBoardingPass fill:#81C784,stroke:#388E3C,stroke-width:2px
    style MarkCheckedIn fill:#66BB6A,stroke:#2E7D32,stroke-width:2px

    style ValidReservation fill:#FFF59D,stroke:#FBC02D,stroke-width:2px
    style CheckTiming fill:#FFF59D,stroke:#FBC02D,stroke-width:2px
    style HasSeat fill:#FFF59D,stroke:#FBC02D,stroke-width:2px
    style ConfirmSeat fill:#FFF59D,stroke:#FBC02D,stroke-width:2px
    style MorePassengers fill:#FFF59D,stroke:#FBC02D,stroke-width:2px

    style TooEarly fill:#FFCCBC,stroke:#E64A19,stroke-width:2px

Activity: Flight Status Update Workflow

flowchart TD
    Start([πŸ›« Flight status change detected]) --> DetermineEvent{πŸ“Š Event type?}

    DetermineEvent -->|Delay| RecordDelay[⏰ Record delay reason & duration]
    DetermineEvent -->|Gate Change| UpdateGate[πŸšͺ Update gate assignment]
    DetermineEvent -->|Cancellation| InitiateCancel[❌ Initiate cancellation]
    DetermineEvent -->|Departed| MarkDeparted[✈️ Mark as departed]
    DetermineEvent -->|Landed| MarkLanded[πŸ›¬ Mark as landed]

    RecordDelay --> UpdateFlightStatus1[πŸ“Š Update flight instance status]
    UpdateGate --> UpdateFlightStatus1
    MarkDeparted --> UpdateFlightStatus1
    MarkLanded --> UpdateFlightStatus1

    InitiateCancel --> MarkCancelled[🚫 Mark flight as cancelled]
    MarkCancelled --> GetAffectedReservations[πŸ“‹ Retrieve all reservations]

    UpdateFlightStatus1 --> GetAffectedReservations

    GetAffectedReservations --> NotifyPassengers{πŸ‘₯ Notify passengers?}
    NotifyPassengers -->|Yes| DetermineNotifType{πŸ“§ Notification type?}
    NotifyPassengers -->|No| LogChange[πŸ“ Log status change]

    DetermineNotifType -->|Delay| SendDelayNotif[πŸ“§ Send delay notification]
    DetermineNotifType -->|Gate Change| SendGateNotif[πŸ“§ Send gate change alert]
    DetermineNotifType -->|Cancellation| SendCancelNotif[πŸ“§ Send cancellation notice]
    DetermineNotifType -->|General Update| SendUpdateNotif[πŸ“§ Send status update]

    SendDelayNotif --> ProcessRebooking{πŸ”„ Auto-rebook available?}
    SendGateNotif --> LogChange
    SendUpdateNotif --> LogChange

    SendCancelNotif --> ProcessRebooking

    ProcessRebooking -->|Yes| FindAlternatives[πŸ” Find alternative flights]
    ProcessRebooking -->|No| InitiateRefund[πŸ’° Initiate refund process]

    FindAlternatives --> OfferRebooking[πŸ“§ Offer rebooking options]
    OfferRebooking --> LogChange

    InitiateRefund --> ProcessRefunds[πŸ’³ Process refunds]
    ProcessRefunds --> LogChange

    LogChange --> UpdateDashboard[πŸ“Š Update operations dashboard]
    UpdateDashboard --> End([βœ… Status update complete])

    style Start fill:#E1F5FE,stroke:#01579B,stroke-width:3px
    style End fill:#C8E6C9,stroke:#2E7D32,stroke-width:3px

    style RecordDelay fill:#FFCC80,stroke:#F57C00,stroke-width:2px
    style UpdateGate fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style InitiateCancel fill:#FFCDD2,stroke:#C62828,stroke-width:2px
    style MarkDeparted fill:#A5D6A7,stroke:#388E3C,stroke-width:2px
    style MarkLanded fill:#81C784,stroke:#2E7D32,stroke-width:2px

    style UpdateFlightStatus1 fill:#CE93D8,stroke:#7B1FA2,stroke-width:2px
    style MarkCancelled fill:#EF9A9A,stroke:#C62828,stroke-width:2px
    style GetAffectedReservations fill:#E1BEE7,stroke:#8E24AA,stroke-width:2px

    style SendDelayNotif fill:#FFE082,stroke:#F9A825,stroke-width:2px
    style SendGateNotif fill:#FFE082,stroke:#F9A825,stroke-width:2px
    style SendCancelNotif fill:#FFE082,stroke:#F9A825,stroke-width:2px
    style SendUpdateNotif fill:#FFE082,stroke:#F9A825,stroke-width:2px

    style FindAlternatives fill:#B3E5FC,stroke:#0277BD,stroke-width:2px
    style OfferRebooking fill:#81D4FA,stroke:#0277BD,stroke-width:2px
    style InitiateRefund fill:#FFAB91,stroke:#D84315,stroke-width:2px
    style ProcessRefunds fill:#FFAB91,stroke:#D84315,stroke-width:2px

    style LogChange fill:#E1BEE7,stroke:#7B1FA2,stroke-width:2px
    style UpdateDashboard fill:#BA68C8,stroke:#6A1B9A,stroke-width:2px

    style DetermineEvent fill:#FFF9C4,stroke:#F9A825,stroke-width:2px
    style NotifyPassengers fill:#FFF9C4,stroke:#F9A825,stroke-width:2px
    style DetermineNotifType fill:#FFF9C4,stroke:#F9A825,stroke-width:2px
    style ProcessRebooking fill:#FFF9C4,stroke:#F9A825,stroke-width:2px

5. High-Level Code Implementation

Java

import java.time.*;
import java.util.*;
import java.math.BigDecimal;

// ============================================================================
// Enums
// ============================================================================

enum FlightStatus {
    SCHEDULED, BOARDING, DEPARTED, IN_AIR, LANDED, ARRIVED,
    DELAYED, CANCELLED, DIVERTED
}

enum ReservationStatus {
    PENDING, CONFIRMED, CHECKED_IN, BOARDING, COMPLETED, CANCELLED
}

enum SeatClass {
    ECONOMY, PREMIUM_ECONOMY, BUSINESS, FIRST_CLASS
}

enum SeatType {
    STANDARD, EXTRA_LEGROOM, EXIT_ROW, BULKHEAD
}

enum PaymentStatus {
    PENDING, AUTHORIZED, COMPLETED, FAILED, REFUNDED
}

enum CrewRole {
    CAPTAIN, FIRST_OFFICER, FLIGHT_ATTENDANT, PURSER
}

// ============================================================================
// Value Objects
// ============================================================================

class Money {
    private final BigDecimal amount;
    private final String currency;

    public Money(BigDecimal amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public Money add(Money other) {
        if (!this.currency.equals(other.currency)) {
            throw new IllegalArgumentException("Currency mismatch");
        }
        return new Money(this.amount.add(other.amount), this.currency);
    }

    public Money multiply(double factor) {
        return new Money(this.amount.multiply(BigDecimal.valueOf(factor)), this.currency);
    }
}

class Duration {
    private final int minutes;

    public Duration(int minutes) {
        this.minutes = minutes;
    }

    public int getMinutes() { return minutes; }
    public int getHours() { return minutes / 60; }
}

// ============================================================================
// Aircraft and Airport
// ============================================================================

class Aircraft {
    private String registrationNumber;
    private String model;
    private String manufacturer;
    private int yearBuilt;
    private SeatConfiguration seatConfiguration;
    private int totalFlightHours;

    public Aircraft(String registration, String model, String manufacturer, int year) {
        this.registrationNumber = registration;
        this.model = model;
        this.manufacturer = manufacturer;
        this.yearBuilt = year;
    }

    public int getTotalSeats() {
        return seatConfiguration.getTotalSeats();
    }

    public List<Seat> getAvailableSeats(FlightInstance instance) {
        return seatConfiguration.getSeats().stream()
            .filter(seat -> !instance.isSeatOccupied(seat))
            .toList();
    }

    public String getRegistrationNumber() { return registrationNumber; }
}

class SeatConfiguration {
    private Map<SeatClass, Integer> seatCounts;
    private List<Seat> seats;

    public SeatConfiguration() {
        this.seatCounts = new HashMap<>();
        this.seats = new ArrayList<>();
    }

    public void addSeat(Seat seat) {
        seats.add(seat);
        seatCounts.merge(seat.getSeatClass(), 1, Integer::sum);
    }

    public List<Seat> getSeatsForClass(SeatClass seatClass) {
        return seats.stream()
            .filter(s -> s.getSeatClass() == seatClass)
            .toList();
    }

    public int getTotalSeats() {
        return seats.size();
    }

    public List<Seat> getSeats() { return seats; }
}

class Seat {
    private String seatNumber;
    private SeatClass seatClass;
    private SeatType seatType;
    private boolean hasExtraLegroom;
    private boolean isWindowSeat;
    private boolean isAisleSeat;

    public Seat(String number, SeatClass seatClass, SeatType type) {
        this.seatNumber = number;
        this.seatClass = seatClass;
        this.seatType = type;
    }

    public String getSeatNumber() { return seatNumber; }
    public SeatClass getSeatClass() { return seatClass; }
    public boolean isWindow() { return isWindowSeat; }
}

class Airport {
    private String code;  // IATA code (e.g., JFK, LAX)
    private String name;
    private String city;
    private String country;
    private List<Gate> gates;

    public Airport(String code, String name, String city, String country) {
        this.code = code;
        this.name = name;
        this.city = city;
        this.country = country;
        this.gates = new ArrayList<>();
    }

    public Gate getAvailableGate(LocalDateTime dateTime) {
        return gates.stream()
            .filter(g -> g.isAvailable(dateTime))
            .findFirst()
            .orElseThrow(() -> new RuntimeException("No available gates"));
    }

    public String getCode() { return code; }
}

class Gate {
    private String gateNumber;
    private String terminal;

    public Gate(String gateNumber, String terminal) {
        this.gateNumber = gateNumber;
        this.terminal = terminal;
    }

    public boolean isAvailable(LocalDateTime dateTime) {
        // Check if gate is not assigned to another flight at this time
        return true; // Simplified
    }

    public String getGateNumber() { return gateNumber; }
}

// ============================================================================
// Flight Scheduling (Strategy Pattern)
// ============================================================================

class Flight {
    private String flightNumber;
    private Airport origin;
    private Airport destination;
    private Duration duration;
    private List<FlightSchedule> schedules;

    public Flight(String number, Airport origin, Airport destination, Duration duration) {
        this.flightNumber = number;
        this.origin = origin;
        this.destination = destination;
        this.duration = duration;
        this.schedules = new ArrayList<>();
    }

    public void addSchedule(FlightSchedule schedule) {
        schedules.add(schedule);
    }

    public List<FlightInstance> createInstances(LocalDate startDate, LocalDate endDate) {
        List<FlightInstance> instances = new ArrayList<>();
        for (FlightSchedule schedule : schedules) {
            instances.addAll(schedule.generateInstances(this, startDate, endDate));
        }
        return instances;
    }

    public String getFlightNumber() { return flightNumber; }
    public Airport getOrigin() { return origin; }
    public Airport getDestination() { return destination; }
    public Duration getDuration() { return duration; }
}

interface FlightSchedule {
    List<FlightInstance> generateInstances(Flight flight, LocalDate startDate, LocalDate endDate);
}

class RecurringSchedule implements FlightSchedule {
    private Set<DayOfWeek> daysOfWeek;
    private LocalTime departureTime;

    public RecurringSchedule(Set<DayOfWeek> days, LocalTime time) {
        this.daysOfWeek = days;
        this.departureTime = time;
    }

    @Override
    public List<FlightInstance> generateInstances(Flight flight, LocalDate startDate, LocalDate endDate) {
        List<FlightInstance> instances = new ArrayList<>();
        LocalDate current = startDate;

        while (!current.isAfter(endDate)) {
            if (daysOfWeek.contains(current.getDayOfWeek())) {
                LocalDateTime departure = LocalDateTime.of(current, departureTime);
                LocalDateTime arrival = departure.plusMinutes(flight.getDuration().getMinutes());

                FlightInstance instance = new FlightInstance(
                    generateInstanceId(flight, departure),
                    flight,
                    departure,
                    arrival
                );
                instances.add(instance);
            }
            current = current.plusDays(1);
        }
        return instances;
    }

    private String generateInstanceId(Flight flight, LocalDateTime departure) {
        return flight.getFlightNumber() + "-" +
               departure.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd"));
    }
}

class CustomSchedule implements FlightSchedule {
    private LocalDate specificDate;
    private LocalTime departureTime;

    public CustomSchedule(LocalDate date, LocalTime time) {
        this.specificDate = date;
        this.departureTime = time;
    }

    @Override
    public List<FlightInstance> generateInstances(Flight flight, LocalDate startDate, LocalDate endDate) {
        if (specificDate.isBefore(startDate) || specificDate.isAfter(endDate)) {
            return List.of();
        }

        LocalDateTime departure = LocalDateTime.of(specificDate, departureTime);
        LocalDateTime arrival = departure.plusMinutes(flight.getDuration().getMinutes());

        FlightInstance instance = new FlightInstance(
            flight.getFlightNumber() + "-SPECIAL-" + specificDate,
            flight,
            departure,
            arrival
        );
        return List.of(instance);
    }
}

class FlightInstance {
    private String instanceId;
    private Flight flight;
    private LocalDateTime departureTime;
    private LocalDateTime arrivalTime;
    private Aircraft aircraft;
    private Gate departureGate;
    private Gate arrivalGate;
    private FlightStatus status;
    private List<CrewAssignment> crewAssignments;
    private Set<Seat> occupiedSeats;

    public FlightInstance(String id, Flight flight, LocalDateTime departure, LocalDateTime arrival) {
        this.instanceId = id;
        this.flight = flight;
        this.departureTime = departure;
        this.arrivalTime = arrival;
        this.status = FlightStatus.SCHEDULED;
        this.crewAssignments = new ArrayList<>();
        this.occupiedSeats = new HashSet<>();
    }

    public void updateStatus(FlightStatus newStatus) {
        this.status = newStatus;
        // Trigger notifications
    }

    public void assignCrew(CrewMember member, CrewRole role) {
        if (!member.isQualifiedFor(this.aircraft)) {
            throw new IllegalArgumentException("Crew member not qualified for this aircraft");
        }
        crewAssignments.add(new CrewAssignment(member, this, role));
    }

    public List<Seat> getAvailableSeats() {
        if (aircraft == null) return List.of();
        return aircraft.getAvailableSeats(this);
    }

    public boolean isSeatOccupied(Seat seat) {
        return occupiedSeats.contains(seat);
    }

    public void occupySeat(Seat seat) {
        occupiedSeats.add(seat);
    }

    public void setAircraft(Aircraft aircraft) { this.aircraft = aircraft; }
    public void setDepartureGate(Gate gate) { this.departureGate = gate; }

    public String getInstanceId() { return instanceId; }
    public Flight getFlight() { return flight; }
    public FlightStatus getStatus() { return status; }
    public Aircraft getAircraft() { return aircraft; }
}

// ============================================================================
// Reservations
// ============================================================================

class Customer {
    private String customerId;
    private String email;
    private String phone;
    private String firstName;
    private String lastName;
    private FrequentFlyerAccount loyaltyAccount;
    private List<Itinerary> travelHistory;

    public Customer(String id, String email, String firstName, String lastName) {
        this.customerId = id;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
        this.travelHistory = new ArrayList<>();
    }

    public Itinerary createItinerary() {
        Itinerary itinerary = new Itinerary(this);
        travelHistory.add(itinerary);
        return itinerary;
    }

    public double getLoyaltyDiscount() {
        return loyaltyAccount != null ? loyaltyAccount.getDiscountRate() : 0.0;
    }

    public String getCustomerId() { return customerId; }
    public String getEmail() { return email; }
}

class FrequentFlyerAccount {
    private String accountNumber;
    private int miles;
    private String tier;  // Silver, Gold, Platinum

    public double getDiscountRate() {
        return switch(tier) {
            case "Platinum" -> 0.15;
            case "Gold" -> 0.10;
            case "Silver" -> 0.05;
            default -> 0.0;
        };
    }
}

class Passenger {
    private String passportNumber;
    private String firstName;
    private String lastName;
    private LocalDate dateOfBirth;
    private String nationality;

    public Passenger(String passport, String firstName, String lastName, LocalDate dob) {
        this.passportNumber = passport;
        this.firstName = firstName;
        this.lastName = lastName;
        this.dateOfBirth = dob;
    }

    public String getFullName() {
        return firstName + " " + lastName;
    }

    public String getPassportNumber() { return passportNumber; }
}

class Reservation {
    private String confirmationNumber;
    private Customer customer;
    private FlightInstance flightInstance;
    private List<SeatAssignment> seatAssignments;
    private ReservationStatus status;
    private Money totalCost;
    private LocalDateTime bookingTime;
    private Payment payment;

    public Reservation(String confirmation, Customer customer, FlightInstance instance) {
        this.confirmationNumber = confirmation;
        this.customer = customer;
        this.flightInstance = instance;
        this.seatAssignments = new ArrayList<>();
        this.status = ReservationStatus.PENDING;
        this.bookingTime = LocalDateTime.now();
    }

    public void confirmReservation() {
        if (status != ReservationStatus.PENDING) {
            throw new IllegalStateException("Can only confirm pending reservations");
        }
        this.status = ReservationStatus.CONFIRMED;
    }

    public Money cancel() {
        if (status == ReservationStatus.COMPLETED || status == ReservationStatus.CANCELLED) {
            throw new IllegalStateException("Cannot cancel this reservation");
        }

        this.status = ReservationStatus.CANCELLED;

        // Calculate refund based on cancellation policy
        long hoursUntilDeparture = java.time.temporal.ChronoUnit.HOURS.between(
            LocalDateTime.now(),
            flightInstance.departureTime
        );

        if (hoursUntilDeparture > 24) {
            return totalCost.multiply(0.9); // 90% refund
        } else if (hoursUntilDeparture > 2) {
            return totalCost.multiply(0.5); // 50% refund
        } else {
            return new Money(BigDecimal.ZERO, "USD"); // No refund
        }
    }

    public void checkIn() {
        if (status != ReservationStatus.CONFIRMED) {
            throw new IllegalStateException("Reservation must be confirmed to check in");
        }
        this.status = ReservationStatus.CHECKED_IN;
    }

    public void addSeatAssignment(SeatAssignment assignment) {
        seatAssignments.add(assignment);
        flightInstance.occupySeat(assignment.getSeat());
    }

    public String getConfirmationNumber() { return confirmationNumber; }
    public ReservationStatus getStatus() { return status; }
}

class SeatAssignment {
    private Passenger passenger;
    private Seat seat;
    private FlightInstance flightInstance;
    private boolean isCheckedIn;

    public SeatAssignment(Passenger passenger, Seat seat, FlightInstance instance) {
        this.passenger = passenger;
        this.seat = seat;
        this.flightInstance = instance;
        this.isCheckedIn = false;
    }

    public void checkIn() {
        this.isCheckedIn = true;
    }

    public Seat getSeat() { return seat; }
    public Passenger getPassenger() { return passenger; }
}

class Itinerary {
    private String itineraryId;
    private Customer customer;
    private List<Reservation> reservations;
    private Money totalPrice;

    public Itinerary(Customer customer) {
        this.itineraryId = UUID.randomUUID().toString();
        this.customer = customer;
        this.reservations = new ArrayList<>();
    }

    public void addReservation(Reservation reservation) {
        reservations.add(reservation);
        calculateTotalCost();
    }

    public Money calculateTotalCost() {
        Money total = new Money(BigDecimal.ZERO, "USD");
        for (Reservation res : reservations) {
            total = total.add(res.totalCost);
        }
        this.totalPrice = total;
        return total;
    }

    public List<Reservation> getReservations() { return reservations; }
}

// ============================================================================
// Crew Management
// ============================================================================

abstract class CrewMember {
    protected String employeeId;
    protected String name;
    protected List<String> certifications;

    public CrewMember(String id, String name) {
        this.employeeId = id;
        this.name = name;
        this.certifications = new ArrayList<>();
    }

    public abstract boolean isQualifiedFor(Aircraft aircraft);

    public String getEmployeeId() { return employeeId; }
}

class Pilot extends CrewMember {
    private String licenseNumber;
    private int totalFlightHours;
    private List<String> aircraftQualifications;

    public Pilot(String id, String name, String license) {
        super(id, name);
        this.licenseNumber = license;
        this.aircraftQualifications = new ArrayList<>();
    }

    @Override
    public boolean isQualifiedFor(Aircraft aircraft) {
        return aircraftQualifications.contains(aircraft.getRegistrationNumber()) ||
               totalFlightHours > 1000;
    }

    public void addAircraftQualification(String aircraftModel) {
        aircraftQualifications.add(aircraftModel);
    }
}

class FlightAttendant extends CrewMember {
    private List<String> languages;
    private int yearsOfExperience;

    public FlightAttendant(String id, String name) {
        super(id, name);
        this.languages = new ArrayList<>();
    }

    @Override
    public boolean isQualifiedFor(Aircraft aircraft) {
        // All flight attendants qualified for all aircraft in this simplified model
        return certifications.contains("SAFETY_CERTIFIED");
    }

    public void addLanguage(String language) {
        languages.add(language);
    }
}

class CrewAssignment {
    private CrewMember crewMember;
    private FlightInstance flightInstance;
    private CrewRole role;

    public CrewAssignment(CrewMember member, FlightInstance instance, CrewRole role) {
        this.crewMember = member;
        this.flightInstance = instance;
        this.role = role;

        if (!validate()) {
            throw new IllegalStateException("Invalid crew assignment");
        }
    }

    public boolean validate() {
        // Validate role matches crew member type
        if (role == CrewRole.CAPTAIN || role == CrewRole.FIRST_OFFICER) {
            return crewMember instanceof Pilot;
        } else {
            return crewMember instanceof FlightAttendant;
        }
    }
}

// ============================================================================
// Pricing Strategy Pattern
// ============================================================================

interface PricingStrategy {
    Money calculatePrice(Reservation reservation, SeatClass seatClass);
}

class BasePricing implements PricingStrategy {
    private Map<SeatClass, Money> baseRates;

    public BasePricing() {
        this.baseRates = new HashMap<>();
        baseRates.put(SeatClass.ECONOMY, new Money(new BigDecimal("200"), "USD"));
        baseRates.put(SeatClass.PREMIUM_ECONOMY, new Money(new BigDecimal("400"), "USD"));
        baseRates.put(SeatClass.BUSINESS, new Money(new BigDecimal("800"), "USD"));
        baseRates.put(SeatClass.FIRST_CLASS, new Money(new BigDecimal("1500"), "USD"));
    }

    @Override
    public Money calculatePrice(Reservation reservation, SeatClass seatClass) {
        Money basePrice = baseRates.get(seatClass);
        double discount = reservation.customer.getLoyaltyDiscount();
        return basePrice.multiply(1.0 - discount);
    }
}

class DemandPricing implements PricingStrategy {
    private PricingStrategy basePricing;

    public DemandPricing(PricingStrategy base) {
        this.basePricing = base;
    }

    @Override
    public Money calculatePrice(Reservation reservation, SeatClass seatClass) {
        Money basePrice = basePricing.calculatePrice(reservation, seatClass);

        double occupancyRate = getOccupancyRate(reservation.flightInstance);
        double demandMultiplier = 1.0;

        if (occupancyRate > 0.85) {
            demandMultiplier = 1.5;
        } else if (occupancyRate > 0.70) {
            demandMultiplier = 1.25;
        } else if (occupancyRate > 0.50) {
            demandMultiplier = 1.1;
        }

        return basePrice.multiply(demandMultiplier);
    }

    private double getOccupancyRate(FlightInstance instance) {
        int total = instance.getAircraft().getTotalSeats();
        int occupied = instance.occupiedSeats.size();
        return (double) occupied / total;
    }
}

class SeasonalPricing implements PricingStrategy {
    private PricingStrategy basePricing;
    private Map<Integer, Double> seasonalMultipliers;

    public SeasonalPricing(PricingStrategy base) {
        this.basePricing = base;
        this.seasonalMultipliers = new HashMap<>();
        // Holiday seasons
        seasonalMultipliers.put(12, 1.4); // December
        seasonalMultipliers.put(7, 1.3);  // July
        seasonalMultipliers.put(8, 1.3);  // August
    }

    @Override
    public Money calculatePrice(Reservation reservation, SeatClass seatClass) {
        Money basePrice = basePricing.calculatePrice(reservation, seatClass);

        int month = reservation.flightInstance.departureTime.getMonthValue();
        double multiplier = seasonalMultipliers.getOrDefault(month, 1.0);

        return basePrice.multiply(multiplier);
    }
}

// ============================================================================
// Payment
// ============================================================================

class Payment {
    private String transactionId;
    private Money amount;
    private String paymentMethod;
    private PaymentStatus status;
    private LocalDateTime timestamp;

    public Payment(Money amount, String method) {
        this.transactionId = UUID.randomUUID().toString();
        this.amount = amount;
        this.paymentMethod = method;
        this.status = PaymentStatus.PENDING;
        this.timestamp = LocalDateTime.now();
    }

    public boolean process() {
        // Payment processing logic
        this.status = PaymentStatus.COMPLETED;
        return true;
    }

    public boolean refund(Money refundAmount) {
        if (status != PaymentStatus.COMPLETED) {
            return false;
        }
        this.status = PaymentStatus.REFUNDED;
        return true;
    }
}

// ============================================================================
// Repository Interfaces
// ============================================================================

interface FlightRepository {
    List<FlightInstance> searchFlights(Airport origin, Airport destination,
                                      LocalDate date);
    FlightInstance findById(String instanceId);
    void save(FlightInstance instance);
}

interface ReservationRepository {
    Reservation findByConfirmation(String confirmationNumber);
    List<Reservation> findByCustomer(String customerId);
    void save(Reservation reservation);
}

Python

from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime, date, time, timedelta
from decimal import Decimal
from enum import Enum
from typing import List, Optional, Set, Dict
from uuid import uuid4


# ============================================================================
# Enums
# ============================================================================

class FlightStatus(Enum):
    SCHEDULED = "scheduled"
    BOARDING = "boarding"
    DEPARTED = "departed"
    IN_AIR = "in_air"
    LANDED = "landed"
    ARRIVED = "arrived"
    DELAYED = "delayed"
    CANCELLED = "cancelled"
    DIVERTED = "diverted"


class ReservationStatus(Enum):
    PENDING = "pending"
    CONFIRMED = "confirmed"
    CHECKED_IN = "checked_in"
    BOARDING = "boarding"
    COMPLETED = "completed"
    CANCELLED = "cancelled"


class SeatClass(Enum):
    ECONOMY = "economy"
    PREMIUM_ECONOMY = "premium_economy"
    BUSINESS = "business"
    FIRST_CLASS = "first_class"


class SeatType(Enum):
    STANDARD = "standard"
    EXTRA_LEGROOM = "extra_legroom"
    EXIT_ROW = "exit_row"
    BULKHEAD = "bulkhead"


class PaymentStatus(Enum):
    PENDING = "pending"
    AUTHORIZED = "authorized"
    COMPLETED = "completed"
    FAILED = "failed"
    REFUNDED = "refunded"


class CrewRole(Enum):
    CAPTAIN = "captain"
    FIRST_OFFICER = "first_officer"
    FLIGHT_ATTENDANT = "flight_attendant"
    PURSER = "purser"


# ============================================================================
# Value Objects
# ============================================================================

@dataclass(frozen=True)
class Money:
    """Immutable money representation"""
    amount: Decimal
    currency: str = "USD"

    def add(self, other: 'Money') -> 'Money':
        if self.currency != other.currency:
            raise ValueError("Currency mismatch")
        return Money(self.amount + other.amount, self.currency)

    def multiply(self, factor: float) -> 'Money':
        return Money(self.amount * Decimal(str(factor)), self.currency)


@dataclass(frozen=True)
class Duration:
    minutes: int

    @property
    def hours(self) -> float:
        return self.minutes / 60


# ============================================================================
# Aircraft and Airport
# ============================================================================

class Seat:
    def __init__(self, seat_number: str, seat_class: SeatClass,
                 seat_type: SeatType) -> None:
        self.seat_number = seat_number
        self.seat_class = seat_class
        self.seat_type = seat_type
        self.has_extra_legroom = seat_type == SeatType.EXTRA_LEGROOM
        self.is_window_seat = seat_number.endswith(('A', 'F'))
        self.is_aisle_seat = seat_number.endswith(('C', 'D'))


class SeatConfiguration:
    def __init__(self) -> None:
        self.seat_counts: Dict[SeatClass, int] = {}
        self.seats: List[Seat] = []

    def add_seat(self, seat: Seat) -> None:
        self.seats.append(seat)
        self.seat_counts[seat.seat_class] = \
            self.seat_counts.get(seat.seat_class, 0) + 1

    def get_seats_for_class(self, seat_class: SeatClass) -> List[Seat]:
        return [s for s in self.seats if s.seat_class == seat_class]

    def get_total_seats(self) -> int:
        return len(self.seats)


class Aircraft:
    def __init__(self, registration: str, model: str,
                 manufacturer: str, year: int) -> None:
        self.registration_number = registration
        self.model = model
        self.manufacturer = manufacturer
        self.year_built = year
        self.seat_configuration: Optional[SeatConfiguration] = None
        self.total_flight_hours = 0

    def get_total_seats(self) -> int:
        return self.seat_configuration.get_total_seats() \
               if self.seat_configuration else 0

    def get_available_seats(self, instance: 'FlightInstance') -> List[Seat]:
        if not self.seat_configuration:
            return []
        return [s for s in self.seat_configuration.seats
                if not instance.is_seat_occupied(s)]


class Gate:
    def __init__(self, gate_number: str, terminal: str) -> None:
        self.gate_number = gate_number
        self.terminal = terminal

    def is_available(self, dt: datetime) -> bool:
        return True  # Simplified


class Airport:
    def __init__(self, code: str, name: str, city: str, country: str) -> None:
        self.code = code
        self.name = name
        self.city = city
        self.country = country
        self.gates: List[Gate] = []

    def get_available_gate(self, dt: datetime) -> Optional[Gate]:
        for gate in self.gates:
            if gate.is_available(dt):
                return gate
        return None


# ============================================================================
# Flight Scheduling (Strategy Pattern)
# ============================================================================

class FlightSchedule(ABC):
    """Strategy interface for flight scheduling"""

    @abstractmethod
    def generate_instances(self, flight: 'Flight',
                          start_date: date, end_date: date) -> List['FlightInstance']:
        pass


class RecurringSchedule(FlightSchedule):
    def __init__(self, days_of_week: Set[int], departure_time: time) -> None:
        self.days_of_week = days_of_week  # 0=Monday, 6=Sunday
        self.departure_time = departure_time

    def generate_instances(self, flight: 'Flight',
                          start_date: date, end_date: date) -> List['FlightInstance']:
        instances = []
        current = start_date

        while current <= end_date:
            if current.weekday() in self.days_of_week:
                departure = datetime.combine(current, self.departure_time)
                arrival = departure + timedelta(minutes=flight.duration.minutes)

                instance = FlightInstance(
                    instance_id=f"{flight.flight_number}-{current.strftime('%Y%m%d')}",
                    flight=flight,
                    departure_time=departure,
                    arrival_time=arrival
                )
                instances.append(instance)

            current += timedelta(days=1)

        return instances


class CustomSchedule(FlightSchedule):
    def __init__(self, specific_date: date, departure_time: time) -> None:
        self.specific_date = specific_date
        self.departure_time = departure_time

    def generate_instances(self, flight: 'Flight',
                          start_date: date, end_date: date) -> List['FlightInstance']:
        if not (start_date <= self.specific_date <= end_date):
            return []

        departure = datetime.combine(self.specific_date, self.departure_time)
        arrival = departure + timedelta(minutes=flight.duration.minutes)

        instance = FlightInstance(
            instance_id=f"{flight.flight_number}-SPECIAL-{self.specific_date}",
            flight=flight,
            departure_time=departure,
            arrival_time=arrival
        )
        return [instance]


class Flight:
    def __init__(self, flight_number: str, origin: Airport,
                 destination: Airport, duration: Duration) -> None:
        self.flight_number = flight_number
        self.origin = origin
        self.destination = destination
        self.duration = duration
        self.schedules: List[FlightSchedule] = []

    def add_schedule(self, schedule: FlightSchedule) -> None:
        self.schedules.append(schedule)

    def create_instances(self, start_date: date, end_date: date) -> List['FlightInstance']:
        instances = []
        for schedule in self.schedules:
            instances.extend(schedule.generate_instances(self, start_date, end_date))
        return instances


class FlightInstance:
    def __init__(self, instance_id: str, flight: Flight,
                 departure_time: datetime, arrival_time: datetime) -> None:
        self.instance_id = instance_id
        self.flight = flight
        self.departure_time = departure_time
        self.arrival_time = arrival_time
        self.aircraft: Optional[Aircraft] = None
        self.departure_gate: Optional[Gate] = None
        self.arrival_gate: Optional[Gate] = None
        self.status = FlightStatus.SCHEDULED
        self.crew_assignments: List['CrewAssignment'] = []
        self.occupied_seats: Set[Seat] = set()

    def update_status(self, new_status: FlightStatus) -> None:
        self.status = new_status

    def assign_crew(self, member: 'CrewMember', role: CrewRole) -> None:
        if not member.is_qualified_for(self.aircraft):
            raise ValueError("Crew member not qualified for this aircraft")
        self.crew_assignments.append(CrewAssignment(member, self, role))

    def get_available_seats(self) -> List[Seat]:
        if not self.aircraft:
            return []
        return self.aircraft.get_available_seats(self)

    def is_seat_occupied(self, seat: Seat) -> bool:
        return seat in self.occupied_seats

    def occupy_seat(self, seat: Seat) -> None:
        self.occupied_seats.add(seat)


# ============================================================================
# Reservations
# ============================================================================

class FrequentFlyerAccount:
    def __init__(self, account_number: str, tier: str = "Basic") -> None:
        self.account_number = account_number
        self.miles = 0
        self.tier = tier

    def get_discount_rate(self) -> float:
        return {
            "Platinum": 0.15,
            "Gold": 0.10,
            "Silver": 0.05,
            "Basic": 0.0
        }.get(self.tier, 0.0)


class Customer:
    def __init__(self, customer_id: str, email: str,
                 first_name: str, last_name: str) -> None:
        self.customer_id = customer_id
        self.email = email
        self.first_name = first_name
        self.last_name = last_name
        self.phone: Optional[str] = None
        self.loyalty_account: Optional[FrequentFlyerAccount] = None
        self.travel_history: List['Itinerary'] = []

    def create_itinerary(self) -> 'Itinerary':
        itinerary = Itinerary(self)
        self.travel_history.append(itinerary)
        return itinerary

    def get_loyalty_discount(self) -> float:
        return self.loyalty_account.get_discount_rate() \
               if self.loyalty_account else 0.0


@dataclass
class Passenger:
    passport_number: str
    first_name: str
    last_name: str
    date_of_birth: date
    nationality: str

    def get_full_name(self) -> str:
        return f"{self.first_name} {self.last_name}"


class SeatAssignment:
    def __init__(self, passenger: Passenger, seat: Seat,
                 flight_instance: FlightInstance) -> None:
        self.passenger = passenger
        self.seat = seat
        self.flight_instance = flight_instance
        self.is_checked_in = False

    def check_in(self) -> None:
        self.is_checked_in = True


class Reservation:
    def __init__(self, confirmation: str, customer: Customer,
                 flight_instance: FlightInstance) -> None:
        self.confirmation_number = confirmation
        self.customer = customer
        self.flight_instance = flight_instance
        self.seat_assignments: List[SeatAssignment] = []
        self.status = ReservationStatus.PENDING
        self.total_cost: Optional[Money] = None
        self.booking_time = datetime.now()
        self.payment: Optional['Payment'] = None

    def confirm_reservation(self) -> None:
        if self.status != ReservationStatus.PENDING:
            raise ValueError("Can only confirm pending reservations")
        self.status = ReservationStatus.CONFIRMED

    def cancel(self) -> Money:
        if self.status in [ReservationStatus.COMPLETED, ReservationStatus.CANCELLED]:
            raise ValueError("Cannot cancel this reservation")

        self.status = ReservationStatus.CANCELLED

        hours_until = (self.flight_instance.departure_time - datetime.now()).total_seconds() / 3600

        if hours_until > 24:
            return self.total_cost.multiply(0.9)
        elif hours_until > 2:
            return self.total_cost.multiply(0.5)
        else:
            return Money(Decimal('0'))

    def check_in(self) -> None:
        if self.status != ReservationStatus.CONFIRMED:
            raise ValueError("Reservation must be confirmed to check in")
        self.status = ReservationStatus.CHECKED_IN

    def add_seat_assignment(self, assignment: SeatAssignment) -> None:
        self.seat_assignments.append(assignment)
        self.flight_instance.occupy_seat(assignment.seat)


class Itinerary:
    def __init__(self, customer: Customer) -> None:
        self.itinerary_id = str(uuid4())
        self.customer = customer
        self.reservations: List[Reservation] = []
        self.total_price: Optional[Money] = None

    def add_reservation(self, reservation: Reservation) -> None:
        self.reservations.append(reservation)
        self.calculate_total_cost()

    def calculate_total_cost(self) -> Money:
        total = Money(Decimal('0'))
        for res in self.reservations:
            if res.total_cost:
                total = total.add(res.total_cost)
        self.total_price = total
        return total


# ============================================================================
# Crew Management
# ============================================================================

class CrewMember(ABC):
    def __init__(self, employee_id: str, name: str) -> None:
        self.employee_id = employee_id
        self.name = name
        self.certifications: List[str] = []

    @abstractmethod
    def is_qualified_for(self, aircraft: Aircraft) -> bool:
        pass


class Pilot(CrewMember):
    def __init__(self, employee_id: str, name: str, license_number: str) -> None:
        super().__init__(employee_id, name)
        self.license_number = license_number
        self.total_flight_hours = 0
        self.aircraft_qualifications: List[str] = []

    def is_qualified_for(self, aircraft: Aircraft) -> bool:
        return (aircraft.model in self.aircraft_qualifications or
                self.total_flight_hours > 1000)

    def add_aircraft_qualification(self, model: str) -> None:
        self.aircraft_qualifications.append(model)


class FlightAttendant(CrewMember):
    def __init__(self, employee_id: str, name: str) -> None:
        super().__init__(employee_id, name)
        self.languages: List[str] = []
        self.years_of_experience = 0

    def is_qualified_for(self, aircraft: Aircraft) -> bool:
        return "SAFETY_CERTIFIED" in self.certifications

    def add_language(self, language: str) -> None:
        self.languages.append(language)


class CrewAssignment:
    def __init__(self, crew_member: CrewMember,
                 flight_instance: FlightInstance, role: CrewRole) -> None:
        self.crew_member = crew_member
        self.flight_instance = flight_instance
        self.role = role

        if not self.validate():
            raise ValueError("Invalid crew assignment")

    def validate(self) -> bool:
        if self.role in [CrewRole.CAPTAIN, CrewRole.FIRST_OFFICER]:
            return isinstance(self.crew_member, Pilot)
        else:
            return isinstance(self.crew_member, FlightAttendant)


# ============================================================================
# Pricing Strategy Pattern
# ============================================================================

class PricingStrategy(ABC):
    @abstractmethod
    def calculate_price(self, reservation: Reservation,
                       seat_class: SeatClass) -> Money:
        pass


class BasePricing(PricingStrategy):
    def __init__(self) -> None:
        self.base_rates = {
            SeatClass.ECONOMY: Money(Decimal('200')),
            SeatClass.PREMIUM_ECONOMY: Money(Decimal('400')),
            SeatClass.BUSINESS: Money(Decimal('800')),
            SeatClass.FIRST_CLASS: Money(Decimal('1500'))
        }

    def calculate_price(self, reservation: Reservation,
                       seat_class: SeatClass) -> Money:
        base_price = self.base_rates[seat_class]
        discount = reservation.customer.get_loyalty_discount()
        return base_price.multiply(1.0 - discount)


class DemandPricing(PricingStrategy):
    def __init__(self, base_pricing: PricingStrategy) -> None:
        self.base_pricing = base_pricing

    def calculate_price(self, reservation: Reservation,
                       seat_class: SeatClass) -> Money:
        base_price = self.base_pricing.calculate_price(reservation, seat_class)

        occupancy = self._get_occupancy_rate(reservation.flight_instance)

        if occupancy > 0.85:
            multiplier = 1.5
        elif occupancy > 0.70:
            multiplier = 1.25
        elif occupancy > 0.50:
            multiplier = 1.1
        else:
            multiplier = 1.0

        return base_price.multiply(multiplier)

    def _get_occupancy_rate(self, instance: FlightInstance) -> float:
        if not instance.aircraft:
            return 0.0
        total = instance.aircraft.get_total_seats()
        occupied = len(instance.occupied_seats)
        return occupied / total if total > 0 else 0.0


class SeasonalPricing(PricingStrategy):
    def __init__(self, base_pricing: PricingStrategy) -> None:
        self.base_pricing = base_pricing
        self.seasonal_multipliers = {
            12: 1.4,  # December
            7: 1.3,   # July
            8: 1.3    # August
        }

    def calculate_price(self, reservation: Reservation,
                       seat_class: SeatClass) -> Money:
        base_price = self.base_pricing.calculate_price(reservation, seat_class)
        month = reservation.flight_instance.departure_time.month
        multiplier = self.seasonal_multipliers.get(month, 1.0)
        return base_price.multiply(multiplier)


# ============================================================================
# Payment
# ============================================================================

class Payment:
    def __init__(self, amount: Money, payment_method: str) -> None:
        self.transaction_id = str(uuid4())
        self.amount = amount
        self.payment_method = payment_method
        self.status = PaymentStatus.PENDING
        self.timestamp = datetime.now()

    def process(self) -> bool:
        self.status = PaymentStatus.COMPLETED
        return True

    def refund(self, refund_amount: Money) -> bool:
        if self.status != PaymentStatus.COMPLETED:
            return False
        self.status = PaymentStatus.REFUNDED
        return True


# ============================================================================
# Repository Interfaces
# ============================================================================

class FlightRepository(ABC):
    @abstractmethod
    def search_flights(self, origin: Airport, destination: Airport,
                      flight_date: date) -> List[FlightInstance]:
        pass

    @abstractmethod
    def find_by_id(self, instance_id: str) -> Optional[FlightInstance]:
        pass

    @abstractmethod
    def save(self, instance: FlightInstance) -> None:
        pass


class ReservationRepository(ABC):
    @abstractmethod
    def find_by_confirmation(self, confirmation: str) -> Optional[Reservation]:
        pass

    @abstractmethod
    def find_by_customer(self, customer_id: str) -> List[Reservation]:
        pass

    @abstractmethod
    def save(self, reservation: Reservation) -> None:
        pass

This implementation demonstrates:

  • SOLID Principles clearly applied throughout
  • Strategy Pattern for flight scheduling and pricing
  • Repository Pattern for data access abstraction
  • Template Method in CrewMember hierarchy
  • Observer Pattern (implied) for notifications
  • Clean separation of concerns with focused classes
  • Rich domain models with business logic
  • Comprehensive type hints and documentation

Comments