LLD - Facade Design Pattern


Facade Design Pattern
The Facade Design Pattern is a structural pattern that provides a simplified, unified interface to a set of complex subsystems.
Blueprint of Facade Design pattern
Facade → Simplified interface to the subsystem
Subsystem classes → Actual code implementation, unaware of Facade
Client → Can access either Facade or Subsystem classes
Example 1: Making Payments
Let’s say a client who wants to process a payment might need to go through these steps:
Encrypt data → Call payments API → Handle retries & logging
This makes every client do these steps = Duplication + Complexity
Before Facade:
encrypt(data);
doPayment(…)
log(…)
retry(…)
Solution with Facade: ✅
Encapsulate this orchestration
Expose simple method -
paymentFacade.makePayment(...)
that handles all the steps
Example 2: Starting a Car
Without Facade:
Client is handling low level tasks
public class Driver {
public static void main(String[] args) {
Engine engine = new Engine();
Lights lights = new Lights();
AC ac = new AC();
engine.start();
lights.turnOn();
ac.turnOn();
}
}
With Facade: ✅
- Client is simplified
- Subsystems are encapsulated
// Subsystems
class Engine {
void start() { System.out.println("Engine started"); }
}
class Lights {
void turnOn() { System.out.println("Lights on"); }
}
class AC {
void turnOn() { System.out.println("AC running"); }
}
// Facade
public class CarFacade {
private Engine engine = new Engine();
private Lights lights = new Lights();
private AC ac = new AC();
public void startCar() {
engine.start();
lights.turnOn();
ac.turnOn();
}
}
// Client
public class Driver {
public static void main(String[] args) {
CarFacade car = new CarFacade();
car.startCar();
}
}
Case Study - Hotel Booking System
In a typical hotel booking flow, multiple steps are involved:
Check room availability
Verify user identity
Process the payment
Book the room
Send booking confirmation
Solution - Using Facade Pattern
Create sub system classes that perform each task
Introduce a
Hotel Booking Facade
class to orchestrate the processExpose a single method
bookHotel(…)
to the client
Github - Facade Design Pattern Code
Subsystems:
// AvailabilityService.java
public class AvailabilityService {
public boolean isRoomAvailable(String roomType) {
System.out.println("Checking availability for room: " + roomType);
return true; // Dummy logic
}
}
// PaymentService.java
public class PaymentService {
public boolean processPayment(String paymentDetails) {
System.out.println("Processing payment with details: " + paymentDetails);
return true; // Dummy logic
}
}
// KYCService.java
public class KYCService {
public boolean verifyUser(String userId) {
System.out.println("Verifying user KYC for ID: " + userId);
return true; // Dummy logic
}
}
// BookingService.java
public class BookingService {
public String bookRoom(String userId, String roomType) {
System.out.println("Booking room for user " + userId + " with type: " + roomType);
return "BOOKING12345"; // Dummy booking ID
}
}
// NotificationService.java
public class NotificationService {
public void sendConfirmation(String userId, String bookingId) {
System.out.println("Sending confirmation to user " + userId + " for booking: " + bookingId);
}
}
Facade:
// HotelBookingFacade.java
public class HotelBookingFacade {
private AvailabilityService availabilityService = new AvailabilityService();
private PaymentService paymentService = new PaymentService();
private KYCService kycService = new KYCService();
private BookingService bookingService = new BookingService();
private NotificationService notificationService = new NotificationService();
public void bookHotel(String userId, String roomType, String paymentDetails) {
System.out.println("Starting hotel booking process...");
if (!availabilityService.isRoomAvailable(roomType)) {
System.out.println("Room not available!");
return;
}
if (!kycService.verifyUser(userId)) {
System.out.println("User verification failed!");
return;
}
if (!paymentService.processPayment(paymentDetails)) {
System.out.println("Payment failed!");
return;
}
String bookingId = bookingService.bookRoom(userId, roomType);
notificationService.sendConfirmation(userId, bookingId);
System.out.println("Booking successful! Booking ID: " + bookingId);
}
}
Client:
// HotelBookingApp.java
public class HotelBookingApp {
public static void main(String[] args) {
HotelBookingFacade bookingFacade = new HotelBookingFacade();
String userId = "USER-001";
String roomType = "Deluxe";
String paymentDetails = "CreditCard: 1234-5678-9101-5678";
bookingFacade.bookHotel(userId, roomType, paymentDetails);
}
}
Output:
Starting hotel booking process...
Checking availability for room: Deluxe
Verifying user KYC for ID: USER-001
Processing payment with details: CreditCard: 1234-5678-9101-5678
Booking room for user USER-001 with type: Deluxe
Sending confirmation to user USER-001 for booking: BOOKING12345
Booking successful! Booking ID: BOOKING12345
Multiple Facade
Lets say you're booking international travel:
You use a TravelFacade that:
Books your flight using FlightBookingFacade
Books your hotel using HotelBookingFacade
Schedules a visa appointment using VisaFacade
Each sub-facade encapsulates its own complexity, and the top-level TravelFacade simply coordinates them.
public class TravelFacade {
private FlightBookingFacade flightBookingFacade = new FlightBookingFacade();
private HotelBookingFacade hotelBookingFacade = new HotelBookingFacade();
private VisaProcessingFacade visaFacade = new VisaProcessingFacade();
public void bookInternationalTrip(String userId, String destination, String paymentDetails) {
System.out.println("Booking international trip to " + destination + " for " + userId);
visaFacade.applyVisa(userId, destination);
flightBookingFacade.bookFlight(userId, destination, paymentDetails);
hotelBookingFacade.bookHotel(userId, "Deluxe", paymentDetails);
System.out.println("International trip booked successfully!");
}
}
Example Use Case: Apache Commons IO - File Utilities
Problem Without Facade:
Reading, copying, writing, or monitoring files requires dealing with low-level Java I/O (Streams, Readers, Buffers), which is verbose and error-prone.
How Facade Helps:FileUtils
and IOUtils
from Apache Commons IO provides simple one-liner methods like copyFile(...)
, readFileToString(...)
, etc., hiding all the stream/reader/exception complexity.
Facade:
Static utility classes in Apache Commons IO that wrap low-level stream operations.
Impact:
Reduces boilerplate, improves readability, and encourages safe file handling practices.
Benefits
Cleaner client code
Hides complexity
Easier testing and mocking
Promotes maintainability
Drawbacks
Risk of becoming a god object if not designed well
Over-abstraction can obscure useful methods
Doesn’t eliminate complexity — just hides it
Facade vs Mediator?
Facade | Mediator |
Client → Facade → Subsystems | Colleagues → Mediator → Other Colleagues |
Simplifies client usage | Coordinates communication between components |
Doesn't manage subsystem interaction between components | Central controller that manages communication |
Facade vs Adapter?
Facade | Adapter |
Simplifies usage by providing a unified, high-level interface | Converts one interface to another so incompatible types can work together |
Hide complexity of subsystems | Make two incompatible interfaces compatible |
When you have a complex system with multiple components | When you need to work with an external class or legacy API with a different interface |
Facade vs Proxy?
Facade | Proxy |
Simplify and unify access to a complex subsystem | Control access to an object (add extra behavior, delay, or restrict access) |
Hide complexity and reduce coupling | Add control (e.g., caching, logging, access control, lazy loading) |
Client knows only the Facade, not the internal components | Client often doesn’t realize it's talking to a proxy instead of the real object |
Subscribe to my newsletter
Read articles from Manish Pushkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Manish Pushkar
Manish Pushkar
Software Engineer - Backend