Design Movie Ticket Booking System

Last Updated: December 19, 2025

Ashish

Ashish Pratap Singh

hard

In this chapter, we will explore the low-level design of a movie ticket booking system in detail.

Let's start by clarifying the requirements:

1. Clarifying Requirements

Before starting the design, it's important to ask thoughtful questions to uncover hidden assumptions and better define the scope of the system.

Here is an example of how a conversation between the candidate and the interviewer might unfold:

After gathering the details, we can summarize the key system requirements.

1.1 Functional Requirements

  • Users can search for shows based on a movie title and a city.
  • The system should support multiple cities, cinemas, screens, and shows.
  • Each screen has a defined layout of seats with different types (e.g., REGULAR, PREMIUM).
  • A user can book one or more available seats for a specific show.
  • Double booking should be prevented.
  • The ticket price should be calculated dynamically based on configurable rules (e.g., seat types)
  • Users can subscribe to movies and receive notifications when booking opens for them.
  • The system must be flexible to support different payment methods.

1.2 Non-Functional Requirements

  • Concurrency: The system must be designed to handle concurrent booking requests gracefully, ensuring data integrity and preventing race conditions like double-booking.
  • Extensibility: The design should be modular. It should be easy to add new pricing strategies (e.g., holiday pricing) or new payment methods without significant changes to the core system.
  • Modularity: The system should follow good object-oriented principles with a clear separation of concerns.
  • Simplified Interface: The system should expose a simple API for clients to interact with, hiding the underlying complexity of the booking, locking, and payment processes.

After the requirements are clear, lets identify the core entities/objects we will have in our system.

2. Identifying Core Entities

Core entities are the fundamental building blocks of our system. We identify them by analyzing key nouns (e.g., movie, theater, screen, seat, user, booking) and actions (e.g., list, search, book, cancel, lock) from the functional requirements. These typically translate into classes, enums, or interfaces in an object-oriented design.

Let’s walk through the functional requirements and extract the relevant entities:

1. Support searching for shows in multiple cities, cinemas, and screens.

This establishes the hierarchical structure of the system's catalog.

  • City: The top-level geographical entity.
  • Cinema: A physical location within a City that contains multiple screens.
  • Screen: A specific auditorium within a Cinema.
  • Seat: The smallest unit within a Screen. It has properties like SeatType (REGULAR, PREMIUM) and SeatStatus (AVAILABLE, BOOKED, LOCKED), which are managed by enums.
  • Movie: Represents the content being shown.
  • Show: The central entity that connects a Movie to a Screen at a specific time. This is what a user ultimately books.

2. A user can book seats for a specific show.

This introduces the core actors and the outcome of the booking process.

  • User: Represents the customer making the booking.
  • Booking: An entity that represents a confirmed transaction, linking a User, a Show, and a specific list of Seats.

3. Prevent double-booking by temporarily locking seats.

This critical concurrency requirement necessitates a dedicated manager for handling seat states.

  • SeatLockManager: A service entity responsible for atomically locking and unlocking seats for a user during the payment process. It prevents race conditions where two users might try to book the same seat simultaneously.

4. Calculate prices dynamically and support multiple payment methods.

These requirements for flexible, interchangeable algorithms are ideal for the Strategy Pattern.

  • PricingStrategy (Interface): Defines a contract for different pricing models (e.g., WeekdayPricingStrategy, WeekendPricingStrategy). A Show is configured with a specific strategy.
  • PaymentStrategy (Interface): Defines a contract for various payment gateways (e.g., CreditCardPaymentStrategy).
  • Payment: An entity to record the details of the financial transaction.

5. Provide a simple, high-level interface to the complex booking workflow.

To manage the orchestration of locking, pricing, payment, and booking confirmation, two key service entities are introduced.

  • BookingManager: Orchestrates the step-by-step workflow of creating a single booking.
  • MovieBookingService: Acts as a Facade and Singleton, providing a unified and simplified entry point for all client interactions, hiding the complexity of the underlying services and data models.

These core entities define the key abstractions of the Movie Ticket Booking System and will guide the structure of your low-level design and class diagrams.

3. Designing Classes and Relationships

This section breaks down the system's architecture into its fundamental classes, their responsibilities, and the relationships that connect them. We also explore the key design patterns that provide robustness and flexibility to the solution.

3.1 Class Definitions

The system is composed of several types of classes, each with a distinct role.

Enums

Enums
  • PaymentStatus: Defines the outcome of a payment transaction (SUCCESS, FAILURE, PENDING).
  • SeatStatus: Represents the state of a seat (AVAILABLE, BOOKED, LOCKED). The LOCKED state is crucial for handling concurrency during the booking process.
  • SeatType: Classifies seats and associates a base price with each type (REGULAR, PREMIUM, RECLINER).

Data Classes

User

Represents a customer of the booking system.

User

City

Represents a geographical city where cinemas are located.

City

Movie

Represents a film, containing its title and duration. It also acts as a Subject in the Observer pattern.

Seat

Represents a single seat in a cinema screen, with properties like row, column, type, and status.

Seat

Screen

A container for a collection of Seats.

Screen

Cinema

Represents a physical movie theater, containing its name, city, and a list of its Screens.

Cinema

Payment

A data object that records the details of a completed payment transaction.

Payment

Booking

Booking

A data class that encapsulates all details of a confirmed booking, including the user, show, seats, and payment information.

It is constructed using the Builder pattern.

Core Classes

Show

Show

Represents a specific screening of a Movie at a particular Screen and startTime. It is associated with a PricingStrategy to determine ticket costs.

SeatLockManager

A critical service responsible for handling concurrency.

SeatLockManager

It temporarily locks seats for a user during the booking process to prevent double-booking, and automatically releases them after a timeout.

BookingManager

An orchestrator class that manages the entire booking workflow.

BookingManager

It uses the SeatLockManager and a PaymentStrategy to ensure a booking is processed atomically and reliably.

MovieBookingService (Singleton & Facade)

The main entry point for the application.

MovieBookingService

It hides the system's internal complexity from the client and provides a simple, unified API for all major operations like searching for shows and booking tickets.

3.2 Class Relationships

The relationships between classes define the system's structure and data flow.

Composition

  • A Cinema is composed of one or more Screens.
  • A Screen is composed of a collection of Seats.
  • The MovieBookingService "has-a" collection of all core entities like Cinemas, Movies, and Shows, managing their lifecycle.

Association

  • A Show is associated with one Movie, one Screen, and one PricingStrategy.
  • A Booking is associated with one User, one Show, and a list of Seats.
  • A MovieSubject (the Movie) is associated with a list of MovieObservers.

Inheritance

  • Movie extends the abstract MovieSubject class.
  • UserObserver implements the MovieObserver interface.
  • Concrete strategy classes (WeekdayPricingStrategy, CreditCardPaymentStrategy, etc.) implement their respective PricingStrategy and PaymentStrategy interfaces.

Dependency

  • The MovieBookingService (Facade) depends on the BookingManager to handle the booking process.
  • The BookingManager depends on the SeatLockManager to handle seat locking and on a PaymentStrategy to process payments.
  • A client depends on the Booking.BookingBuilder to construct a Booking object.

3.3 Key Design Patterns

Strategy Pattern

This pattern is used to make core algorithms interchangeable.

Pricing

PricingStrategy

The PricingStrategy allows different pricing models (e.g., weekday vs. weekend) to be applied to a Show without changing the Show or BookingManager classes.

Payment

PaymentStrategy

The PaymentStrategy allows different payment methods (e.g., Credit Card, UPI) to be used for a booking.

Observer Pattern

This pattern is used to notify users about movie updates.

Movie Observer

The Movie (Subject) can notify all subscribed UserObservers when an event occurs (e.g., bookings open), decoupling the movie entity from the user notification logic.

Builder Pattern

The Booking.BookingBuilder is used for the step-by-step construction of a Booking object. This is ideal for an object with multiple required fields, ensuring it is created in a valid and consistent state.

Facade Pattern

The MovieBookingService class serves as a facade. It provides a simple, high-level API (findShows, bookTickets) that hides the complex internal workflows involving seat locking, payment processing, and data management.

Singleton Pattern

MovieBookingService is implemented as a singleton to ensure there is a single, globally accessible point of control for the entire booking system. This centralizes the management of all data and services.

3.4 Full Class Diagram

Movie Booking System Class Diagram

4. Implementation

4.1 Enums

These enums standardize constants used across the system

1class PaymentStatus(Enum):
2    SUCCESS = "SUCCESS"
3    FAILURE = "FAILURE"
4    PENDING = "PENDING"
5
6
7class SeatStatus(Enum):
8    AVAILABLE = "AVAILABLE"
9    BOOKED = "BOOKED"
10    LOCKED = "LOCKED"  # Temporarily held during booking process
11
12
13class SeatType(Enum):
14    REGULAR = 50.0
15    PREMIUM = 80.0
16    RECLINER = 120.0
17
18    def get_price(self) -> float:
19        return self.value
  • SeatType maps each seat type to a price.
  • SeatStatus enables clear transitions during the booking process.
  • PaymentStatus helps track payment outcomes.

4.2 User

1class User:
2    def __init__(self, name: str, email: str):
3        self.id = str(uuid.uuid4())
4        self.name = name
5        self.email = email
6
7    def get_id(self) -> str:
8        return self.id
9
10    def get_name(self) -> str:
11        return self.name

4.3 City

1class City:
2    def __init__(self, city_id: str, name: str):
3        self.id = city_id
4        self.name = name
5
6    def get_id(self) -> str:
7        return self.id
8
9    def get_name(self) -> str:
10        return self.name

4.4 Movie

1class Movie(MovieSubject):
2    def __init__(self, movie_id: str, title: str, duration_in_minutes: int):
3        super().__init__()
4        self.id = movie_id
5        self.title = title
6        self.duration_in_minutes = duration_in_minutes
7
8    def get_id(self) -> str:
9        return self.id
10
11    def get_title(self) -> str:
12        return self.title

4.5 Seat

1class Seat:
2    def __init__(self, seat_id: str, row: int, col: int, seat_type: SeatType):
3        self.id = seat_id
4        self.row = row
5        self.col = col
6        self.type = seat_type
7        self.status = SeatStatus.AVAILABLE
8
9    def get_id(self) -> str:
10        return self.id
11
12    def get_row(self) -> int:
13        return self.row
14
15    def get_col(self) -> int:
16        return self.col
17
18    def get_type(self) -> SeatType:
19        return self.type
20
21    def get_status(self) -> SeatStatus:
22        return self.status
23
24    def set_status(self, status: SeatStatus) -> None:
25        self.status = status

4.6 Screen

1class Screen:
2    def __init__(self, screen_id: str):
3        self.id = screen_id
4        self.seats: List[Seat] = []
5
6    def add_seat(self, seat: Seat) -> None:
7        self.seats.append(seat)
8
9    def get_id(self) -> str:
10        return self.id
11
12    def get_seats(self) -> List[Seat]:
13        return self.seats

4.7 Cinema

1class Cinema:
2    def __init__(self, cinema_id: str, name: str, city: City, screens: List[Screen]):
3        self.id = cinema_id
4        self.name = name
5        self.city = city
6        self.screens = screens
7
8    def get_id(self) -> str:
9        return self.id
10
11    def get_name(self) -> str:
12        return self.name
13
14    def get_city(self) -> City:
15        return self.city
16
17    def get_screens(self) -> List[Screen]:
18        return self.screens

4.8 Show

1class Show:
2    def __init__(self, show_id: str, movie: Movie, screen: Screen, start_time: datetime, pricing_strategy: PricingStrategy):
3        self.id = show_id
4        self.movie = movie
5        self.screen = screen
6        self.start_time = start_time
7        self.pricing_strategy = pricing_strategy
8
9    def get_id(self) -> str:
10        return self.id
11
12    def get_movie(self) -> Movie:
13        return self.movie
14
15    def get_screen(self) -> Screen:
16        return self.screen
17
18    def get_start_time(self) -> datetime:
19        return self.start_time
20
21    def get_pricing_strategy(self) -> PricingStrategy:
22        return self.pricing_strategy

4.9 Payment

1class Payment:
2    def __init__(self, amount: float, status: PaymentStatus, transaction_id: str):
3        self.id = str(uuid.uuid4())
4        self.amount = amount
5        self.status = status
6        self.transaction_id = transaction_id
7
8    def get_status(self) -> PaymentStatus:
9        return self.status

4.10 Booking

1class Booking:
2    def __init__(self, booking_id: str, user: User, show: Show, seats: List[Seat], total_amount: float, payment: Payment):
3        self.id = booking_id
4        self.user = user
5        self.show = show
6        self.seats = seats
7        self.total_amount = total_amount
8        self.payment = payment
9
10    def confirm_booking(self) -> None:
11        """Marks seats as BOOKED upon successful booking creation"""
12        for seat in self.seats:
13            seat.set_status(SeatStatus.BOOKED)
14
15    def get_id(self) -> str:
16        return self.id
17
18    def get_user(self) -> User:
19        return self.user
20
21    def get_show(self) -> Show:
22        return self.show
23
24    def get_seats(self) -> List[Seat]:
25        return self.seats
26
27    def get_total_amount(self) -> float:
28        return self.total_amount
29
30    def get_payment(self) -> Payment:
31        return self.payment
32
33    class BookingBuilder:
34        def __init__(self):
35            self.id: Optional[str] = None
36            self.user: Optional[User] = None
37            self.show: Optional[Show] = None
38            self.seats: Optional[List[Seat]] = None
39            self.total_amount: Optional[float] = None
40            self.payment: Optional[Payment] = None
41
42        def set_id(self, booking_id: str) -> 'Booking.BookingBuilder':
43            self.id = booking_id
44            return self
45
46        def set_user(self, user: User) -> 'Booking.BookingBuilder':
47            self.user = user
48            return self
49
50        def set_show(self, show: Show) -> 'Booking.BookingBuilder':
51            self.show = show
52            return self
53
54        def set_seats(self, seats: List[Seat]) -> 'Booking.BookingBuilder':
55            self.seats = seats
56            return self
57
58        def set_total_amount(self, total_amount: float) -> 'Booking.BookingBuilder':
59            self.total_amount = total_amount
60            return self
61
62        def set_payment(self, payment: Payment) -> 'Booking.BookingBuilder':
63            self.payment = payment
64            return self
65
66        def build(self) -> 'Booking':
67            # Validations can be added here
68            return Booking(self.id, self.user, self.show, self.seats, self.total_amount, self.payment)

4.11 Observer

This pattern allows users to subscribe to movie updates, such as when booking opens. The Movie (Subject) is completely decoupled from the User (Observer). The Movie doesn't know what a User is; it only knows it has a list of MovieObservers to notify.

1class MovieObserver(ABC):
2    @abstractmethod
3    def update(self, movie: 'Movie') -> None:
4        pass
5
6class MovieSubject:
7    def __init__(self):
8        self.observers: List[MovieObserver] = []
9
10    def add_observer(self, observer: MovieObserver) -> None:
11        self.observers.append(observer)
12
13    def remove_observer(self, observer: MovieObserver) -> None:
14        if observer in self.observers:
15            self.observers.remove(observer)
16
17    def notify_observers(self) -> None:
18        for observer in self.observers:
19            observer.update(self)
20
21class UserObserver(MovieObserver):
22    def __init__(self, user: User):
23        self.user = user
24
25    def update(self, movie: Movie) -> None:
26        print(f"Notification for {self.user.get_name()} ({self.user.get_id()}): Movie '{movie.get_title()}' is now available for booking!")

4.12 PricingStrategy

The Strategy pattern is used to define a family of algorithms, encapsulate each one, and make them interchangeable. This is perfect for pricing and payment, which can have multiple variations.

1class PricingStrategy(ABC):
2    @abstractmethod
3    def calculate_price(self, seats: List[Seat]) -> float:
4        pass
5
6class WeekdayPricingStrategy(PricingStrategy):
7    def calculate_price(self, seats: List[Seat]) -> float:
8        return sum(seat.get_type().get_price() for seat in seats)
9
10class WeekendPricingStrategy(PricingStrategy):
11    WEEKEND_SURCHARGE = 1.2  # 20% surcharge
12
13    def calculate_price(self, seats: List[Seat]) -> float:
14        base_price = sum(seat.get_type().get_price() for seat in seats)
15        return base_price * self.WEEKEND_SURCHARGE

This pattern decouples the context (a Show or a BookingManager) from the concrete implementation of the algorithm. The Show doesn't need to know how to calculate a weekend price; it just calls calculatePrice() on its configured strategy object.

4.13 Payment Strategy

1class PaymentStrategy(ABC):
2    @abstractmethod
3    def pay(self, amount: float) -> Payment:
4        pass
5
6
7class CreditCardPaymentStrategy(PaymentStrategy):
8    def __init__(self, card_number: str, cvv: str):
9        self.card_number = card_number
10        self.cvv = cvv
11
12    def pay(self, amount: float) -> Payment:
13        print(f"Processing credit card payment of ${amount:.2f}")
14        # Simulate payment gateway interaction
15        payment_success = random.random() > 0.05  # 95% success rate
16        return Payment(
17            amount,
18            PaymentStatus.SUCCESS if payment_success else PaymentStatus.FAILURE,
19            f"TXN_{uuid.uuid4()}"
20        )

4.14 SeatLockManager

1class SeatLockManager:
2    def __init__(self):
3        self.locked_seats: Dict[Show, Dict[Seat, str]] = {}
4        self.executor = ThreadPoolExecutor(max_workers=5)
5        self.LOCK_TIMEOUT_SECONDS = 0.5  # 0.5 seconds. In real world, timeout would be in minutes
6
7    def lock_seats(self, show: Show, seats: List[Seat], user_id: str) -> None:
8        # Use a lock per show to ensure atomicity for that specific show
9        show_lock = getattr(show, '_lock', None)
10        if show_lock is None:
11            show._lock = threading.Lock()
12            show_lock = show._lock
13
14        with show_lock:
15            # Check if any of the requested seats are already locked or booked
16            for seat in seats:
17                if seat.get_status() != SeatStatus.AVAILABLE:
18                    print(f"Seat {seat.get_id()} is not available.")
19                    return
20
21            # Lock the seats
22            for seat in seats:
23                seat.set_status(SeatStatus.LOCKED)
24
25            if show not in self.locked_seats:
26                self.locked_seats[show] = {}
27            
28            for seat in seats:
29                self.locked_seats[show][seat] = user_id
30
31            # Schedule a task to unlock the seats after a timeout
32            self.executor.submit(self._unlock_after_timeout, show, seats, user_id)
33            print(f"Locked seats: {[seat.get_id() for seat in seats]} for user {user_id}")
34
35    def _unlock_after_timeout(self, show: Show, seats: List[Seat], user_id: str) -> None:
36        time.sleep(self.LOCK_TIMEOUT_SECONDS)
37        self.unlock_seats(show, seats, user_id)
38
39    def unlock_seats(self, show: Show, seats: List[Seat], user_id: str) -> None:
40        show_lock = getattr(show, '_lock', None)
41        if show_lock is None:
42            return
43
44        with show_lock:
45            show_locks = self.locked_seats.get(show)
46            if show_locks is not None:
47                for seat in seats:
48                    # Only unlock if it's still locked by the same user (prevents race conditions)
49                    if seat in show_locks and show_locks[seat] == user_id:
50                        del show_locks[seat]
51                        if seat.get_status() == SeatStatus.LOCKED:
52                            seat.set_status(SeatStatus.AVAILABLE)
53                            print(f"Unlocked seat: {seat.get_id()} due to timeout.")
54                        else:
55                            print(f"Unlocked seat: {seat.get_id()} due to booking completion.")
56                
57                if not show_locks:
58                    del self.locked_seats[show]
59
60    def shutdown(self) -> None:
61        print("Shutting down SeatLockProvider scheduler.")
62        self.executor.shutdown(wait=True)

4.15 BookingManager

The BookingManager orchestrates the entire booking workflow.

1class BookingManager:
2    def __init__(self, seat_lock_manager: SeatLockManager):
3        self.seat_lock_manager = seat_lock_manager
4
5    def create_booking(self, user: User, show: Show, seats: List[Seat], payment_strategy: PaymentStrategy) -> Optional[Booking]:
6        # 1. Lock the seats
7        self.seat_lock_manager.lock_seats(show, seats, user.get_id())
8
9        # 2. Calculate the total price
10        total_amount = show.get_pricing_strategy().calculate_price(seats)
11
12        # 3. Process Payment
13        payment = payment_strategy.pay(total_amount)
14
15        # 4. If payment is successful, create the booking
16        if payment.get_status() == PaymentStatus.SUCCESS:
17            booking = Booking.BookingBuilder() \
18                .set_user(user) \
19                .set_show(show) \
20                .set_seats(seats) \
21                .set_total_amount(total_amount) \
22                .set_payment(payment) \
23                .build()
24
25            # 5. Confirm the booking (mark seats as BOOKED)
26            booking.confirm_booking()
27
28            # Clean up the lock map
29            self.seat_lock_manager.unlock_seats(show, seats, user.get_id())
30
31            return booking
32        else:
33            print("Payment failed. Please try again.")
34            return None

BookingManager defines the strict, sequential workflow for a booking: lock -> calculate price -> process payment -> create booking -> confirm. This ensures a consistent and reliable process.

4.16 MovieBookingService

This class is a Singleton that provides a simplified, high-level API for clients.

1class MovieBookingService:
2    _instance: Optional['MovieBookingService'] = None
3    _lock = threading.Lock()
4
5    def __new__(cls):
6        if cls._instance is None:
7            with cls._lock:
8                if cls._instance is None:
9                    cls._instance = super().__new__(cls)
10        return cls._instance
11
12    def __init__(self):
13        if hasattr(self, 'initialized'):
14            return
15
16        self.cities: Dict[str, City] = {}
17        self.cinemas: Dict[str, Cinema] = {}
18        self.movies: Dict[str, Movie] = {}
19        self.users: Dict[str, User] = {}
20        self.shows: Dict[str, Show] = {}
21
22        self.seat_lock_manager = SeatLockManager()
23        self.booking_manager = BookingManager(self.seat_lock_manager)
24        self.initialized = True
25
26    @classmethod
27    def get_instance(cls) -> 'MovieBookingService':
28        return cls()
29
30    def get_booking_manager(self) -> BookingManager:
31        return self.booking_manager
32
33    # Data Management Methods
34    def add_city(self, city_id: str, name: str) -> City:
35        city = City(city_id, name)
36        self.cities[city.get_id()] = city
37        return city
38
39    def add_cinema(self, cinema_id: str, name: str, city_id: str, screens: List[Screen]) -> Cinema:
40        city = self.cities[city_id]
41        cinema = Cinema(cinema_id, name, city, screens)
42        self.cinemas[cinema.get_id()] = cinema
43        return cinema
44
45    def add_movie(self, movie: Movie) -> None:
46        self.movies[movie.get_id()] = movie
47
48    def add_show(self, show_id: str, movie: Movie, screen: Screen, start_time: datetime, pricing_strategy: PricingStrategy) -> Show:
49        show = Show(show_id, movie, screen, start_time, pricing_strategy)
50        self.shows[show.get_id()] = show
51        return show
52
53    def create_user(self, name: str, email: str) -> User:
54        user = User(name, email)
55        self.users[user.get_id()] = user
56        return user
57
58    def book_tickets(self, user_id: str, show_id: str, desired_seats: List[Seat], payment_strategy: PaymentStrategy) -> Optional[Booking]:
59        return self.booking_manager.create_booking(
60            self.users[user_id],
61            self.shows[show_id],
62            desired_seats,
63            payment_strategy
64        )
65
66    # Search Functionality
67    def find_shows(self, movie_title: str, city_name: str) -> List[Show]:
68        result = []
69        for show in self.shows.values():
70            if show.get_movie().get_title().lower() == movie_title.lower():
71                cinema = self._find_cinema_for_show(show)
72                if cinema and cinema.get_city().get_name().lower() == city_name.lower():
73                    result.append(show)
74        return result
75
76    def _find_cinema_for_show(self, show: Show) -> Optional[Cinema]:
77        # This is inefficient. In a real system, shows would have a direct link to the cinema.
78        # For this example, we traverse the cinema list.
79        for cinema in self.cinemas.values():
80            if show.get_screen() in cinema.get_screens():
81                return cinema
82        return None
83
84    def shutdown(self) -> None:
85        self.seat_lock_manager.shutdown()
86        print("MovieTicketBookingSystem has been shut down.")
  • Facade Pattern: The facade hides the immense complexity of the system. A client (like a UI controller) doesn't need to know about SeatLockManager or BookingManager; it just calls the simple bookTickets method.

4.17 MovieBookingDemo

The demo class validates the entire system by simulating a user's booking journey.

1class MovieBookingDemo:
2  @staticmethod
3  def main():
4      # Setup
5      service = MovieBookingService.get_instance()
6
7      nyc = service.add_city("city1", "New York")
8      la = service.add_city("city2", "Los Angeles")
9
10      # 2. Add movies
11      matrix = Movie("M1", "The Matrix", 120)
12      avengers = Movie("M2", "Avengers: Endgame", 170)
13      service.add_movie(matrix)
14      service.add_movie(avengers)
15
16      # Add Seats for a Screen
17      screen1 = Screen("S1")
18
19      for i in range(1, 11):
20          seat_type = SeatType.REGULAR if i <= 5 else SeatType.PREMIUM
21          screen1.add_seat(Seat(f"A{i}", 1, i, seat_type))
22          screen1.add_seat(Seat(f"B{i}", 2, i, seat_type))
23
24      # Add Cinemas
25      amc_nyc = service.add_cinema("cinema1", "AMC Times Square", nyc.get_id(), [screen1])
26
27      # Add Shows
28      matrix_show = service.add_show("show1", matrix, screen1, datetime.now() + timedelta(hours=2), WeekdayPricingStrategy())
29      avengers_show = service.add_show("show2", avengers, screen1, datetime.now() + timedelta(hours=5), WeekdayPricingStrategy())
30
31      # User and Observer Setup
32      alice = service.create_user("Alice", "[email protected]")
33      alice_observer = UserObserver(alice)
34      avengers.add_observer(alice_observer)
35
36      # Simulate movie release
37      print("\n--- Notifying Observers about Movie Release ---")
38      avengers.notify_observers()
39
40      # User Story: Alice books tickets
41      print("\n--- Alice's Booking Flow ---")
42      city_name = "New York"
43      movie_title = "Avengers: Endgame"
44
45      # 1. Search for shows
46      available_shows = service.find_shows(movie_title, city_name)
47      if not available_shows:
48          print(f"No shows found for {movie_title} in {city_name}")
49          return
50      
51      selected_show = available_shows[0]  # Alice selects the first show
52
53      # 2. View available seats
54      available_seats = [seat for seat in selected_show.get_screen().get_seats() if seat.get_status() == SeatStatus.AVAILABLE]
55      print(f"Available seats for '{selected_show.get_movie().get_title()}' at {selected_show.get_start_time()}: {[seat.get_id() for seat in available_seats]}")
56
57      # 3. Select seats
58      desired_seats = [available_seats[2], available_seats[3]]
59      print(f"Alice selects seats: {[seat.get_id() for seat in desired_seats]}")
60
61      # 4. Book Tickets
62      booking = service.book_tickets(
63          alice.get_id(),
64          selected_show.get_id(),
65          desired_seats,
66          CreditCardPaymentStrategy("1234-5678-9876-5432", "123")
67      )
68
69      if booking:
70          print("\n--- Booking Successful! ---")
71          print(f"Booking ID: {booking.get_id()}")
72          print(f"User: {booking.get_user().get_name()}")
73          print(f"Movie: {booking.get_show().get_movie().get_title()}")
74          print(f"Seats: {[seat.get_id() for seat in booking.get_seats()]}")
75          print(f"Total Amount: ${booking.get_total_amount()}")
76          print(f"Payment Status: {booking.get_payment().get_status().value}")
77      else:
78          print("Booking failed.")
79
80      # 5. Verify seat status after booking
81      print("\nSeat status after Alice's booking:")
82      for seat in desired_seats:
83          print(f"Seat {seat.get_id()} status: {seat.get_status().value}")
84
85      # 6. Shut down the system to release resources like the scheduler.
86      service.shutdown()
87
88
89if __name__ == "__main__":
90    MovieBookingDemo.main()

5. Run and Test

Files24
core
entities
enums
observers
strategies
movie_booking_demo.py
main
movie_booking_service.py
movie_booking_demo.pymain
Output

6. Quiz

Design Movie Booking System Quiz

1 / 21
Multiple Choice

Which entity forms the link between a Movie, a Screen, and a specific time in a Movie Booking System?

How helpful was this article?

Comments (1)


0/2000
Sort by
The Cap21 days ago

I see one issue in this system is that you are maintaining seatStatus inside seat which seems to be incorrect as same seat can be used for two different shows, so may be its better to maintain a data structure inside the shows which stores the list of bookedSeats,


because in your current approach if you change the seatStatus then other shows will not be able to see the seats as well

Copilot extension content script