OOD - Airline Management System
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 configurationSeatConfiguration- Defines seat layout for different aircraft typesAirport- Airport entity with code, name, location, terminal informationGate- Boarding gate assignments
Flight Scheduling (Strategy Pattern):
Flight- Master flight route (e.g., AA101 from JFK to LAX)FlightSchedule(interface) - Strategy for generating flight instancesRecurringSchedule- Daily/weekly recurring flightsCustomSchedule- One-time special flightsFlightInstance- Specific occurrence of a flight with date, time, aircraft, crew
Reservation Management:
Reservation- Booking entity with passengers, seats, paymentItinerary- Collection of reservations forming a complete tripPassenger- Individual traveler with personal detailsSeat- Physical seat with class, type, and featuresSeatAssignment- Links passenger to specific seat on flight instance
Crew Management:
CrewMember(abstract) - Base for all crewPilot,FlightAttendant- Specific crew typesCrewAssignment- Assigns crew to flight instance with role validation
Payment & Notification:
Payment- Handles payment processingPricingStrategy(interface) - Dynamic pricing based on demand, season, etc.NotificationService- Observer pattern for alerts
Repositories (Repository Pattern):
FlightRepository- Flight data accessReservationRepository- Reservation persistenceAircraftRepository- 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:
- Strategy Pattern:
FlightScheduleallows different scheduling algorithms (recurring vs custom) - Strategy Pattern:
PricingStrategyenables dynamic pricing based on various factors - Repository Pattern: Abstracts data access for flights and reservations
- Observer Pattern:
NotificationServicenotifies customers of flight changes - Factory Pattern: (Implied) Creating different crew member types
- 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
FlightScheduleorCrewMembersubclass 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