# Hotel Management System

#### Low-Level Design (LLD) for a **Hotel Management System** in Java

The **Hotel Management System** (HMS) is an application designed to manage hotel room bookings, guests, and the overall operation of a hotel. This system allows users to reserve rooms, check availability, and manage bookings from reservation to check-out. The system also includes features for managing room types, prices, and availability to prevent overbooking.

In this LLD, we will address the following core functionalities:

1. **Entities and Relationships**: Design classes for rooms, guests, and bookings, and how these entities relate to each other.
2. **Booking Process**: Handling the booking from reservation to check-out.
3. **Room Availability**: Managing and tracking room availability to avoid overbooking.
4. **Design Patterns Used**: We will implement **Factory Pattern**, **Singleton Pattern**, **Observer Pattern**, and **Strategy Pattern** to structure the system.

***

#### **Entities and Relationships**

**Key Entities:**

* **Room**: Represents a hotel room with attributes like room type, availability, price, and status (booked or available).
* **Guest**: Represents a guest who makes the booking and stays in the room.
* **Booking**: Represents a booking made by a guest, including booking date, check-in date, and check-out date.
* **Payment**: Represents the payment made by the guest for the booking.
* **Hotel**: Represents the hotel and its operations, including room inventory and availability.

***

#### **Classes and Data Structures**

**1. Room Class**

The **Room** class represents a room in the hotel with its attributes, such as room type, availability, and price.

```java
enum RoomType {
    SINGLE, DOUBLE, SUITE
}

class Room {
    private int roomId;
    private RoomType type;
    private double pricePerNight;
    private boolean isAvailable;

    public Room(int roomId, RoomType type, double pricePerNight) {
        this.roomId = roomId;
        this.type = type;
        this.pricePerNight = pricePerNight;
        this.isAvailable = true;  // Initially, room is available
    }

    public int getRoomId() {
        return roomId;
    }

    public RoomType getType() {
        return type;
    }

    public double getPricePerNight() {
        return pricePerNight;
    }

    public boolean isAvailable() {
        return isAvailable;
    }

    public void bookRoom() {
        this.isAvailable = false;
    }

    public void releaseRoom() {
        this.isAvailable = true;
    }
}
```

**2. Guest Class**

The **Guest** class represents a guest with personal details and a list of bookings.

```java
class Guest {
    private String name;
    private String email;
    private List<Booking> bookings;

    public Guest(String name, String email) {
        this.name = name;
        this.email = email;
        this.bookings = new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

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

    public void addBooking(Booking booking) {
        bookings.add(booking);
    }
}
```

**3. Booking Class**

The **Booking** class represents a booking made by a guest for a particular room, including check-in and check-out details.

```java
import java.time.LocalDate;

class Booking {
    private int bookingId;
    private Room room;
    private Guest guest;
    private LocalDate checkInDate;
    private LocalDate checkOutDate;
    private double totalAmount;

    public Booking(int bookingId, Room room, Guest guest, LocalDate checkInDate, LocalDate checkOutDate) {
        this.bookingId = bookingId;
        this.room = room;
        this.guest = guest;
        this.checkInDate = checkInDate;
        this.checkOutDate = checkOutDate;
        this.totalAmount = room.getPricePerNight() * (checkOutDate.getDayOfYear() - checkInDate.getDayOfYear());
    }

    public Room getRoom() {
        return room;
    }

    public Guest getGuest() {
        return guest;
    }

    public LocalDate getCheckInDate() {
        return checkInDate;
    }

    public LocalDate getCheckOutDate() {
        return checkOutDate;
    }

    public double getTotalAmount() {
        return totalAmount;
    }

    public void cancelBooking() {
        this.room.releaseRoom();
    }
}
```

**4. Payment Class**

The **Payment** class represents the payment details for a booking.

```java
class Payment {
    private double amount;
    private boolean isPaid;

    public Payment(double amount) {
        this.amount = amount;
        this.isPaid = false;
    }

    public double getAmount() {
        return amount;
    }

    public boolean isPaid() {
        return isPaid;
    }

    public void makePayment() {
        this.isPaid = true;
        System.out.println("Payment of " + amount + " made successfully.");
    }
}
```

**5. Hotel Class (Singleton Pattern)**

The **Hotel** class represents the entire hotel. This class ensures that the hotel’s room availability is managed and prevents overbooking by acting as a Singleton.

```java
import java.util.List;

class Hotel {
    private static Hotel instance;
    private List<Room> rooms;

    private Hotel(List<Room> rooms) {
        this.rooms = rooms;
    }

    public static Hotel getInstance(List<Room> rooms) {
        if (instance == null) {
            instance = new Hotel(rooms);
        }
        return instance;
    }

    public List<Room> getRooms() {
        return rooms;
    }

    public Room findAvailableRoom(RoomType type) {
        for (Room room : rooms) {
            if (room.getType() == type && room.isAvailable()) {
                return room;
            }
        }
        return null;
    }
}
```

**6. BookingManager Class (Factory Pattern)**

The **BookingManager** class handles the booking operations. It acts as a factory to create bookings for guests.

```java
class BookingManager {
    private Hotel hotel;

    public BookingManager(Hotel hotel) {
        this.hotel = hotel;
    }

    public Booking createBooking(Guest guest, RoomType roomType, LocalDate checkInDate, LocalDate checkOutDate) {
        Room room = hotel.findAvailableRoom(roomType);
        if (room == null) {
            System.out.println("No available rooms for the requested type.");
            return null;
        }
        room.bookRoom();
        Booking booking = new Booking(generateBookingId(), room, guest, checkInDate, checkOutDate);
        guest.addBooking(booking);
        return booking;
    }

    private int generateBookingId() {
        return (int) (Math.random() * 10000);
    }
}
```

**7. Notification System (Observer Pattern)**

The **NotificationSystem** is responsible for notifying guests when their booking is confirmed or canceled.

```java
interface Observer {
    void update(String message);
}

class GuestObserver implements Observer {
    private Guest guest;

    public GuestObserver(Guest guest) {
        this.guest = guest;
    }

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

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

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

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

***

#### **Booking Process**

**Booking Flow:**

1. **Guest Searches** for a room based on type (e.g., single, double, suite).
2. **BookingManager** searches for an available room of the desired type.
3. If an available room is found, a **Booking** is created, and the room is marked as booked.
4. The **Payment** class processes the payment for the booking.
5. The **GuestObserver** in the **NotificationSystem** sends a confirmation message to the guest.

**Checkout Flow:**

1. **Guest** checks out.
2. The room is released, and the booking is canceled.
3. The **Payment** class is marked as paid.

***

#### **Room Availability & Avoiding Overbooking**

To avoid overbooking, the system checks room availability each time a booking request is made. Rooms are marked as unavailable once booked, and the system ensures that no room can be double-booked. The **Hotel** class tracks the availability status of each room, and the **BookingManager** uses this information to only allow booking if rooms are available.

***

#### **Design Patterns Used**

1. **Singleton Pattern**: The **Hotel** class uses the Singleton Pattern to ensure there is only one instance of the hotel that manages room inventory.
2. **Factory Pattern**: The **BookingManager** class implements the Factory Pattern to create booking instances based on user input and available rooms.
3. **Observer Pattern**: The **NotificationSystem** implements the Observer Pattern to notify guests of booking status changes (confirmation, cancellation, etc.).
4. **Strategy Pattern**: If there were different booking strategies (e.g., early-bird, last-minute deals), the **Strategy Pattern** could be applied to select a pricing strategy dynamically.

***

#### **Conclusion**

The **Hotel Management System** is designed to efficiently manage rooms, bookings, and guests. It uses several design patterns to ensure scalability and maintainability:

* The **Singleton Pattern** ensures a single point of management for the hotel.
* The **Factory Pattern** is used to create bookings based on the available rooms.
* The **Observer Pattern** notifies guests of changes in their booking status.
* The **Strategy Pattern** (if applicable) can be used for dynamic booking pricing.

This design ensures smooth operations, proper room availability management, and a good user experience while preventing overbooking and maintaining system flexibility.
