Transactional / OOD• Patterns: Factory, Observer, Strategy
Hotel Management
Hard
Problem Summary
Design a Hotel Reservation and Management System managing multi-tier rooms (Standard, Deluxe, Suite), booking calendars, dynamic seasonal pricing, and housekeeping room turnover.
Functional Scope
- Manage room categories: Standard, Deluxe, Suite, Presidential.
- Date-range availability search preventing overlapping double-bookings.
- Pluggable tariff pricing strategy (Weekday, Weekend, High-season, Corporate).
- Check-in and keycard generation.
- Observer pattern for housekeeping staff notification when guests checkout.
Entity-Relationship (ER) Schema
Hotel [1] --> [*] Room Hotel [1] --> [1] BookingManager Booking [1] --> [1] Room Booking [1] --> [1] Guest Hotel [1] --> [1] TariffStrategy
Design Approach
Apply the Strategy pattern for seasonal dynamic pricing and the Observer pattern to synchronize housekeeping workflows upon checkout.
Core Classes & Models
Hotel (Top-level hotel facade managing rooms and bookings)Room (RoomNo, RoomType: STANDARD, DELUXE, SUITE, Status: AVAILABLE, BOOKED, DIRTY)Booking (BookingId, room, guest, checkIn, checkOut, billAmount)TariffStrategy (WeekendSurgeTariff, HolidayTariff)HousekeepingObserver (Notifies cleaning staff on checkout)
Code Blueprint
89 lines/**
* Low-Level Design: Hotel Management System
* Design Patterns Applied:
* - Factory Pattern: Room generation (Standard, Deluxe, Suite)
* - Observer Pattern: Housekeeping alerts and reservation notifications
* - Strategy Pattern: Seasonal dynamic room tariff pricing
*/
import java.util.*;
enum RoomType { STANDARD, DELUXE, SUITE }
enum RoomStatus { VACANT, OCCUPIED, CLEANING }
// --- [DESIGN PATTERN: Strategy] Dynamic room pricing strategy ---
interface TariffStrategy {
double calculatePrice(RoomType type, boolean isHighSeason);
}
class SeasonalTariffStrategy implements TariffStrategy {
@Override
public double calculatePrice(RoomType type, boolean isHighSeason) {
double base = switch (type) {
case STANDARD -> 80.0;
case DELUXE -> 150.0;
case SUITE -> 300.0;
};
return isHighSeason ? base * 1.4 : base;
}
}
// --- [DESIGN PATTERN: Observer] Housekeeping observer ---
interface HousekeepingObserver {
void onCheckout(String roomNumber);
}
class HousekeepingService implements HousekeepingObserver {
@Override
public void onCheckout(String roomNumber) {
System.out.println("🧹 [Housekeeping] Room " + roomNumber + " scheduled for sanitation.");
}
}
class Room {
private final String number;
private final RoomType type;
private RoomStatus status = RoomStatus.VACANT;
public Room(String number, RoomType type) { this.number = number; this.type = type; }
public String getNumber() { return number; }
public RoomType getType() { return type; }
public RoomStatus getStatus() { return status; }
public void setStatus(RoomStatus status) { this.status = status; }
}
class Hotel {
private final Map<String, Room> rooms = new HashMap<>();
private final TariffStrategy tariffStrategy = new SeasonalTariffStrategy();
private final List<HousekeepingObserver> observers = new ArrayList<>();
public void addRoom(Room r) { rooms.put(r.getNumber(), r); }
public void addObserver(HousekeepingObserver o) { observers.add(o); }
public void checkIn(String roomNumber) {
Room r = rooms.get(roomNumber);
if (r != null && r.getStatus() == RoomStatus.VACANT) {
r.setStatus(RoomStatus.OCCUPIED);
System.out.println("🏨 Checked into Room " + roomNumber);
}
}
public void checkOut(String roomNumber) {
Room r = rooms.get(roomNumber);
if (r != null) {
r.setStatus(RoomStatus.CLEANING);
for (HousekeepingObserver o : observers) o.onCheckout(roomNumber);
}
}
}
public class Main {
public static void main(String[] args) {
Hotel hotel = new Hotel();
hotel.addObserver(new HousekeepingService());
hotel.addRoom(new Room("101", RoomType.DELUXE));
hotel.checkIn("101");
hotel.checkOut("101");
}
}