Let’s create a complete example of a Hotel Management System that demonstrates the SOLID principles. This example will cover various aspects of a hotel management system, including room management, booking, and notification services.
Example: Hotel Management System
Step 1: Define the Domain Models
We’ll start with the core models: Room
, Booking
, and Customer
.
// Room class
class Room {
private int roomNumber;
private String roomType; // e.g., "Single", "Double", "Suite"
private boolean isAvailable;
public Room(int roomNumber, String roomType) {
this.roomNumber = roomNumber;
this.roomType = roomType;
this.isAvailable = true; // By default, a room is available
}
public int getRoomNumber() {
return roomNumber;
}
public String getRoomType() {
return roomType;
}
public boolean isAvailable() {
return isAvailable;
}
public void setAvailable(boolean available) {
isAvailable = available;
}
}
// Customer class
class Customer {
private String name;
private String email;
public Customer(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}
Step 2: Booking Class
The Booking
class is responsible for managing room bookings.
import java.util.Date;
class Booking {
private Room room;
private Customer customer;
private Date startDate;
private Date endDate;
public Booking(Room room, Customer customer, Date startDate, Date endDate) {
this.room = room;
this.customer = customer;
this.startDate = startDate;
this.endDate = endDate;
}
public Room getRoom() {
return room;
}
public Customer getCustomer() {
return customer;
}
public Date getStartDate() {
return startDate;
}
public Date getEndDate() {
return endDate;
}
}
Step 3: Hotel Class
The Hotel
class manages rooms and bookings and follows the Single Responsibility Principle (SRP).
import java.util.ArrayList;
import java.util.List;
class Hotel {
private List<Room> rooms;
private List<Booking> bookings;
public Hotel() {
this.rooms = new ArrayList<>();
this.bookings = new ArrayList<>();
}
public void addRoom(Room room) {
rooms.add(room);
}
public List<Room> getAvailableRooms() {
List<Room> availableRooms = new ArrayList<>();
for (Room room : rooms) {
if (room.isAvailable()) {
availableRooms.add(room);
}
}
return availableRooms;
}
public void bookRoom(Room room, Customer customer, Date startDate, Date endDate) {
if (room.isAvailable()) {
room.setAvailable(false);
Booking booking = new Booking(room, customer, startDate, endDate);
bookings.add(booking);
} else {
System.out.println("Room is not available!");
}
}
public List<Booking> getBookings() {
return bookings;
}
}
Step 4: NotificationService Interface and Implementations
To adhere to the Open/Closed Principle (OCP), we will create an interface for notifications.
interface NotificationService {
void notifyCustomer(Customer customer, String message);
}
class EmailNotificationService implements NotificationService {
@Override
public void notifyCustomer(Customer customer, String message) {
System.out.println("Sending email to " + customer.getEmail() + ": " + message);
}
}
class SMSNotificationService implements NotificationService {
@Override
public void notifyCustomer(Customer customer, String message) {
System.out.println("Sending SMS to " + customer.getName() + ": " + message);
}
}
Step 5: BookingManager Class
The BookingManager
class handles bookings and notifications. It encapsulates the logic related to booking management and adheres to the SOLID principles.
class BookingManager {
private Hotel hotel;
private NotificationService notificationService;
public BookingManager(Hotel hotel, NotificationService notificationService) {
this.hotel = hotel;
this.notificationService = notificationService;
}
public void bookRoom(Room room, Customer customer, Date startDate, Date endDate) {
hotel.bookRoom(room, customer, startDate, endDate);
notificationService.notifyCustomer(customer, "Your booking for room " + room.getRoomNumber() + " is confirmed.");
}
}
Step 6: Main Application
Now, let’s put everything together in a main application to demonstrate the functionality.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HotelManagementApplication {
public static void main(String[] args) throws ParseException {
// Create hotel
Hotel hotel = new Hotel();
// Add rooms
hotel.addRoom(new Room(101, "Single"));
hotel.addRoom(new Room(102, "Double"));
hotel.addRoom(new Room(103, "Suite"));
// Create customers
Customer alice = new Customer("Alice", "alice@example.com");
Customer bob = new Customer("Bob", "bob@example.com");
// Choose a notification service
NotificationService notificationService = new EmailNotificationService(); // or new SMSNotificationService();
// Create booking manager
BookingManager bookingManager = new BookingManager(hotel, notificationService);
// Simulate room booking
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date startDate = dateFormat.parse("2024-10-01");
Date endDate = dateFormat.parse("2024-10-05");
bookingManager.bookRoom(hotel.getAvailableRooms().get(0), alice, startDate, endDate); // Book room 101 for Alice
bookingManager.bookRoom(hotel.getAvailableRooms().get(0), bob, startDate, endDate); // Attempt to book room 101 for Bob
}
}
Summary of SOLID Principles Applied
-
Single Responsibility Principle (SRP):
Room
,Customer
, andBooking
classes each have a single responsibility.Hotel
manages room and booking logic.BookingManager
handles the booking process and notifications.
-
Open/Closed Principle (OCP):
- The
NotificationService
interface allows for new notification methods (like push notifications) to be added without modifying existing code.
- The
-
Liskov Substitution Principle (LSP):
- Any implementation of the
NotificationService
can be used interchangeably without affecting the behavior of theBookingManager
. For example, you can switch fromEmailNotificationService
toSMSNotificationService
seamlessly.
- Any implementation of the
-
Interface Segregation Principle (ISP):
- The
NotificationService
interface is focused, ensuring that clients only implement the methods they need. For instance, if we later create aPushNotificationService
, it will only implement the notification method without being burdened with unrelated methods.
- The
-
Dependency Inversion Principle (DIP):
BookingManager
depends on theNotificationService
abstraction, not on concrete implementations. This decoupling allows for easier testing and swapping of notification services.
Conclusion
This complete example illustrates the application of all five SOLID principles in a hotel management system. By following these principles, the system is modular, maintainable, and extensible. Each component is responsible for a specific function, and the design allows for easy adaptation as new requirements emerge, such as adding different types of notifications or additional features related to room management and customer services.