Facade Pattern
BeginnerProvides a simplified interface to a complex subsystem, hiding its internal complexity from clients.
Overview
The Facade pattern introduces a high-level interface that makes a complex subsystem easier to use. The Facade does not encapsulate the subsystem — advanced clients can still access subsystem classes directly. It reduces the number of objects clients deal with and decouples clients from subsystem internals. Common in layered architectures: a Service class is a Facade over repositories, validators, event publishers, and external APIs. Spring's JdbcTemplate is a Facade over raw JDBC. The key benefit is simplified usage, not feature restriction.
Facade Implementation
Define a Facade class that composes the subsystem classes. The Facade methods orchestrate calls to subsystem components in the correct order. Clients call the Facade; they do not need to know subsystem details.
// Complex subsystem classes
public class InventoryService {
public boolean reserveStock(String productId, int qty) {
System.out.println("Reserving " + qty + " units of " + productId);
return true;
}
public void releaseReservation(String productId, int qty) {
System.out.println("Releasing reservation for " + productId);
}
}
public class PaymentService {
public String processPayment(String userId, double amount) {
System.out.println("Processing payment of " + amount + " for " + userId);
return "txn-" + System.currentTimeMillis();
}
public void refund(String transactionId) {
System.out.println("Refunding transaction " + transactionId);
}
}
public class ShippingService {
public String createShipment(String orderId, String address) {
System.out.println("Creating shipment for order " + orderId + " to " + address);
return "ship-" + orderId;
}
}
public class NotificationService {
public void sendOrderConfirmation(String userId, String orderId) {
System.out.println("Sending confirmation to user " + userId + " for order " + orderId);
}
}
// Facade — simplifies the multi-step order placement process
public class OrderFacade {
private final InventoryService inventory;
private final PaymentService payment;
private final ShippingService shipping;
private final NotificationService notifier;
public OrderFacade(InventoryService inventory, PaymentService payment,
ShippingService shipping, NotificationService notifier) {
this.inventory = inventory;
this.payment = payment;
this.shipping = shipping;
this.notifier = notifier;
}
// One-call interface hiding the 4-step orchestration
public String placeOrder(String userId, String productId,
int qty, double amount, String address) {
String orderId = "ORD-" + System.currentTimeMillis();
if (!inventory.reserveStock(productId, qty)) {
throw new IllegalStateException("Out of stock: " + productId);
}
String txnId;
try {
txnId = payment.processPayment(userId, amount);
} catch (RuntimeException e) {
inventory.releaseReservation(productId, qty);
throw e;
}
shipping.createShipment(orderId, address);
notifier.sendOrderConfirmation(userId, orderId);
return orderId;
}
}
// Client — one line instead of coordinating four subsystems
OrderFacade facade = new OrderFacade(
new InventoryService(), new PaymentService(),
new ShippingService(), new NotificationService());
String orderId = facade.placeOrder("user-1", "LLD-BOOK", 1, 499.0, "Pune, India");Facade in Spring (Service Layer)
In a Spring application, the @Service layer acts as a Facade over JPA repositories, external REST clients, event publishers, and validators. Controllers should call only the service (Facade), never repositories directly.
@Service
@Transactional
public class CourseEnrollmentService { // Facade for the enrollment subsystem
private final CourseRepository courseRepo;
private final EnrollmentRepository enrollmentRepo;
private final PaymentClient paymentClient; // external HTTP call
private final ApplicationEventPublisher events;
public CourseEnrollmentService(CourseRepository courseRepo,
EnrollmentRepository enrollmentRepo,
PaymentClient paymentClient,
ApplicationEventPublisher events) {
this.courseRepo = courseRepo;
this.enrollmentRepo = enrollmentRepo;
this.paymentClient = paymentClient;
this.events = events;
}
public EnrollmentResponse enroll(String userId, String courseId) {
Course course = courseRepo.findById(courseId)
.orElseThrow(() -> new CourseNotFoundException(courseId));
if (enrollmentRepo.existsByUserIdAndCourseId(userId, courseId)) {
throw new AlreadyEnrolledException(userId, courseId);
}
PaymentResult payment = paymentClient.charge(userId, course.getPrice());
Enrollment enrollment = enrollmentRepo.save(
Enrollment.of(userId, courseId, payment.getTransactionId()));
events.publishEvent(new EnrollmentCreatedEvent(enrollment));
return EnrollmentResponse.from(enrollment);
}
}Key Points to Remember
- 1Facade simplifies complex subsystems — does not prevent direct access to subsystem classes.
- 2In Spring, the @Service layer is a Facade over repositories, clients, and event publishers.
- 3Facade reduces coupling between clients and subsystem internals (changes in subsystem do not affect clients).
- 4Unlike Adapter, Facade wraps a whole subsystem, not one incompatible class.
- 5JdbcTemplate is a Facade over raw JDBC: it hides connection management, statement creation, and result set iteration.
Interview Questions
Sign in to ask AriaWhat is the difference between Facade and Adapter patterns?
How does the Facade pattern support the principle of least knowledge (Law of Demeter)?
Is Spring's JdbcTemplate an example of Facade? Explain.
Can a Facade introduce performance problems? How?
Ask Aria about Facade Pattern
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.