Design (LLD) a Movie Ticket Booking System - Machine Coding

Design (LLD) a Movie Ticket Booking System - Machine Coding

istockphoto-1177049680-612x612.jpeg

Movie Ticket Booking System

An online movie ticket booking system facilitates the purchasing of movie tickets to its customers. E-ticketing systems allow customers to browse through movies currently playing and book seats, anywhere and anytime.

Features

Our ticket booking service should meet the following requirements:

  • It should be able to list the cities where affiliate cinemas are located.

  • Each cinema can have multiple halls and each hall can run one movie show at a time.

  • Each Movie will have multiple shows.

  • Customers should be able to search movies by their title, language, genre, release date, and city name.

  • Once the customer selects a movie, the service should display the cinemas running that movie and its available shows.

  • The customer should be able to select a show at a particular cinema and book their tickets.

  • The service should show the customer the seating arrangement of the cinema hall.

  • The customer should be able to select multiple seats according to their preference.

  • The customer should be able to distinguish between available seats and booked ones.

  • The system should send notifications whenever there is a new movie, as well as when a booking is made or canceled.

  • Customers of our system should be able to pay with credit cards or cash.

  • The system should ensure that no two customers can reserve the same seat.

  • Customers should be able to add a discount coupon to their payment.

Rough Solution (LLD-Machine Coding)

// Enum classes remain the same
public enum BookingStatus {
    REQUESTED, PENDING, CONFIRMED, CHECKED_IN, CANCELED, ABANDONED
}

public enum SeatType {
    REGULAR, PREMIUM, ACCESSIBLE, SHIPPED, EMERGENCY_EXIT, OTHER
}

public enum AccountStatus {
    ACTIVE, BLOCKED, BANNED, COMPROMISED, ARCHIVED, UNKNOWN
}

public enum PaymentStatus {
    UNPAID, PENDING, COMPLETED, FILLED, DECLINED, CANCELLED, ABANDONED, SETTLING, SETTLED, REFUNDED
}

// Supporting classes for address and account
public class Address {
    private String streetAddress;
    private String city;
    private String state;
    private String zipCode;
    private String country;
}

public class Account {
    private String id;
    private String password;
    private AccountStatus status;

    public boolean resetPassword() {
        System.out.println("Password reset.");
        return true;
    }
}

// Abstract Person class
public abstract class Person {
    private String name;
    private Address address;
    private String email;
    private String phone;
    private Account account;

    public Person(String name, Account account) {
        this.name = name;
        this.account = account;
    }

    public String getName() {
        return name;
    }
}

// Observer Pattern for Notifications
interface Observer {
    void update(String message);
}

class Customer extends Person implements Observer {
    private List<Booking> bookings;

    public Customer(String name, Account account) {
        super(name, account);
        bookings = new ArrayList<>();
    }

    @Override
    public void update(String message) {
        System.out.println("Notification for " + getName() + ": " + message);
    }

    public boolean makeBooking(Booking booking) {
        bookings.add(booking);
        System.out.println("Booking made successfully.");
        return true;
    }

    public List<Booking> getBookings() {
        return bookings;
    }
}

class SystemNotifier {
    private List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

// Factory Method Pattern for creating Movies, Shows, and Bookings
abstract class BookingFactory {
    public abstract Booking createBooking(Show show, List<ShowSeat> seats);
}

class RegularBookingFactory extends BookingFactory {
    @Override
    public Booking createBooking(Show show, List<ShowSeat> seats) {
        return new Booking(show, seats);
    }
}

class AdminFactory {
    public Admin createAdmin(String name, Account account) {
        return new Admin(name, account);
    }

    public Movie createMovie(String title, String description, Admin admin) {
        return new Movie(title, description, admin);
    }

    public Show createShow(Movie movie, Date startTime, CinemaHall hall) {
        return new Show(movie, startTime, hall);
    }
}

// Command Pattern for booking and payment operations
interface Command {
    void execute();
}

class CreateBookingCommand implements Command {
    private FrontDeskOfficer officer;
    private Booking booking;

    public CreateBookingCommand(FrontDeskOfficer officer, Booking booking) {
        this.officer = officer;
        this.booking = booking;
    }

    @Override
    public void execute() {
        officer.createBooking(booking);
    }
}

class CancelBookingCommand implements Command {
    private Booking booking;

    public CancelBookingCommand(Booking booking) {
        this.booking = booking;
    }

    @Override
    public void execute() {
        booking.cancel();
    }
}

class MakePaymentCommand implements Command {
    private Payment payment;
    private Booking booking;

    public MakePaymentCommand(Payment payment, Booking booking) {
        this.payment = payment;
        this.booking = booking;
    }

    @Override
    public void execute() {
        booking.makePayment(payment);
    }
}

// Strategy Pattern for searching movies
interface SearchStrategy {
    List<Movie> search(Catalog catalog, String query);
}

class TitleSearchStrategy implements SearchStrategy {
    @Override
    public List<Movie> search(Catalog catalog, String title) {
        return catalog.searchByTitle(title);
    }
}

class GenreSearchStrategy implements SearchStrategy {
    @Override
    public List<Movie> search(Catalog catalog, String genre) {
        return catalog.searchByGenre(genre);
    }
}

class LanguageSearchStrategy implements SearchStrategy {
    @Override
    public List<Movie> search(Catalog catalog, String language) {
        return catalog.searchByLanguage(language);
    }
}

// Template Method Pattern for Payment Processing
abstract class Payment {
    protected double amount;
    protected PaymentStatus status;

    public final void processPayment() {
        initiatePayment();
        confirmPayment();
        updatePaymentStatus();
    }

    protected abstract void initiatePayment();

    private void confirmPayment() {
        System.out.println("Payment confirmed.");
    }

    private void updatePaymentStatus() {
        this.status = PaymentStatus.COMPLETED;
        System.out.println("Payment status updated to COMPLETED.");
    }
}

class CreditCardPayment extends Payment {
    @Override
    protected void initiatePayment() {
        System.out.println("Processing credit card payment of amount: " + amount);
    }
}

class DebitCardPayment extends Payment {
    @Override
    protected void initiatePayment() {
        System.out.println("Processing debit card payment of amount: " + amount);
    }
}

// Supporting classes and interfaces

public class Booking {
    private String bookingNumber;
    private int numberOfSeats;
    private Date createdOn;
    private BookingStatus status;
    private Show show;
    private List<ShowSeat> seats;
    private Payment payment;

    public Booking(Show show, List<ShowSeat> seats) {
        this.show = show;
        this.seats = seats;
        this.status = BookingStatus.REQUESTED;
    }

    public Show getShow() {
        return show;
    }

    public boolean makePayment(Payment payment) {
        this.payment = payment;
        payment.processPayment();
        this.status = BookingStatus.CONFIRMED;
        return true;
    }

    public boolean cancel() {
        this.status = BookingStatus.CANCELED;
        System.out.println("Booking has been canceled.");
        return true;
    }

    public boolean assignSeats(List<ShowSeat> seats) {
        this.seats = seats;
        System.out.println("Seats assigned.");
        return true;
    }
}

public class Show {
    private Movie movie;
    private Date startTime;
    private CinemaHall hall;

    public Show(Movie movie, Date startTime, CinemaHall hall) {
        this.movie = movie;
        this.startTime = startTime;
        this.hall = hall;
    }

    public Movie getMovie() {
        return movie;
    }
}

public class Movie {
    private String title;
    private String description;
    private Admin movieAddedBy;

    public Movie(String title, String description, Admin movieAddedBy) {
        this.title = title;
        this.description = description;
        this.movieAddedBy = movieAddedBy;
    }

    public String getTitle() {
        return title;
    }
}

public class FrontDeskOfficer extends Person {
    public FrontDeskOfficer(String name, Account account) {
        super(name, account);
    }

    public boolean createBooking(Booking booking) {
        System.out.println("Booking created for show: " + booking.getShow().getMovie().getTitle());
        return true;
    }
}

public class Admin extends Person {
    public Admin(String name, Account account) {
        super(name, account);
    }

    public boolean addMovie(Movie movie) {
        System.out.println("Movie " + movie.getTitle() + " added.");
        return true;
    }

    public boolean addShow(Show show) {
        System.out.println("Show added for movie: " + show.getMovie().getTitle());
        return true;
    }

    public boolean blockUser(Customer customer) {
        System.out.println("Customer " + customer.getName() + " blocked.");
        return true;
    }
}

/

// Main class for demonstrating the design
public class Main {
    public static void main(String[] args) {
        // Create an Admin using Factory Method
        AdminFactory adminFactory = new AdminFactory();
        Account adminAccount = new Account();
        Admin admin = adminFactory.createAdmin("John Doe", adminAccount);

        // Create a movie and show
        Movie movie = adminFactory.createMovie("Inception", "Sci-fi Thriller", admin);
        CinemaHall hall = new CinemaHall();
        Show show = adminFactory.createShow(movie, new Date(), hall);

        // Create a booking using Command Pattern
        BookingFactory bookingFactory = new RegularBookingFactory();
        List<ShowSeat> seats = new ArrayList<>();
        Booking booking = bookingFactory.createBooking(show, seats);

        FrontDeskOfficer officer = new FrontDeskOfficer("Jane Doe", new Account());
        Command createBookingCommand = new CreateBookingCommand(officer, booking);
        createBookingCommand.execute();

        // Process payment using Template Method Pattern
        Payment payment = new CreditCardPayment();
        payment.processPayment();

        // Notify customers using Observer Pattern
        SystemNotifier notifier = new SystemNotifier();
        Customer customer = new Customer("Alice", new Account());
        notifier.addObserver(customer);
        notifier.notifyObservers("New movie added: " + movie.getTitle());
    }
}

Did you find this article valuable?

Support Subhahu Jain by becoming a sponsor. Any amount is appreciated!