LESSON 5.5
Facade
Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
14 min read
Real-world analogy
When ordering a hot pepperoni pizza, you do not telephone the dairy farm for cheese, the flour mill for dough, the tomato wholesaler for sauce, and coordinate with an independent delivery courier. You open a food delivery application or call the pizzeria front desk. The front desk acts as a facade: it takes your order, handles payment, coordinates the kitchen, tracks the oven timer, and assigns a courier, presenting you with a single point of interaction.
The problem
You are building an e-commerce platform. When a customer confirms their shopping cart, the system must coordinate multiple complex subsystem services:
InventoryService: Verify stock and reserve SKUs.PaymentService: Authorize credit card or digital wallet transaction.FraudDetector: Score IP address, device fingerprint, and velocity.ShippingService: Book warehouse fulfillment and generate tracking label.NotificationService: Send confirmation email and push notification.
Without a Facade, every client (the web storefront, mobile app, recurring subscription worker, customer support portal) must manually orchestrate all five services:
// Naive implementation: Client directly coupled to all subsystem services
class MobileCheckoutController {
checkout(user, cart) {
const fraud = new FraudDetector();
if (fraud.isFraudulent(user, cart)) throw new Error("Fraud detected");
const inventory = new InventoryService();
if (!inventory.checkStock(cart.items)) throw new Error("Out of stock");
inventory.reserve(cart.items);
const payment = new PaymentService();
const charge = payment.charge(user.billing, cart.total);
if (!charge.success) {
inventory.release(cart.items);
throw new Error("Payment failed");
}
const shipping = new ShippingService();
const tracking = shipping.schedulePickup(user.address, cart.items);
const notifier = new NotificationService();
notifier.sendOrderConfirmation(user.email, charge.id, tracking.code);
}
}public class Example {
static class MobileCheckoutController {
// High coupling: Controller must instantiate, configure, and orchestrate
// 5+ disparate subsystems, repeating the same sequence across all client apps.
public void checkout(String user, double amount) {
System.out.println("Manually coordinating 5 disparate services...");
}
}
public
This architecture produces tight coupling between client UI controllers and backend subsystems. If ShippingService updates its API or requires address validation, every client caller must be modified.
The solution
The Facade pattern provides a unified, higher-level interface over a collection of subsystem interfaces. It encapsulates the complex interactions, ordering rules, and error recovery workflows behind a single method call.
- Facade (
OrderCheckoutFacade): High-level entry point delegating to subsystem components. - Subsystem Classes (
Inventory,Payment,Shipping,Notification): Independent modules unaware of the Facade's existence. - Client: Interacts solely with the Facade for common workflows, while retaining the freedom to invoke specific subsystems directly for advanced tasks.
Step-by-step implementation
Step 1: Define the independent subsystem components
The subsystem classes perform their specific domain tasks independently.
Step 2: Assemble the facade orchestrating the subsystem
The facade holds references to the subsystem instances and exposes a clean high-level method.
Step 3: Callers interact with the simplified facade
Clients need only one line of code to execute the entire end-to-end workflow.
const facade = new OrderCheckoutFacade(new InventoryService(), new PaymentService());
const confirmation = facade.placeOrder({ token: "card_tok_123" }, ["item_1"], 49.99);
console.log(`Order status: ${confirmation.orderId}`);public class Example {
static class InventoryService { public boolean reserve(int c) {
The complete example
Here is the complete runnable example demonstrating video conversion across complex subsystem decoders and encoders.
--- Starting conversion: raw_footage.mkv ---
Demuxer: Extracted audio stream from raw_footage.mkv
Demuxer: Extracted video stream from raw_footage.mkv
AudioMixer: Transcoded audio to AAC @ 192kbps
VideoTranscoder: Compressed video using H.264 at 1080p
Mp4Muxer: Packaged video and audio into container -> raw_footage.mp4
--- Completed conversion: raw_footage.mp4 ---
--- Starting conversion: mobile_recording.avi ---
Demuxer: Extracted audio stream from mobile_recording.avi
Demuxer: Extracted video stream from mobile_recording.avi
AudioMixer: Transcoded audio to AAC @ 192kbps
VideoTranscoder: Compressed video using H.265 at 4K
Variations
Facade vs adapter
Engineers often confuse Facade and Adapter because both wrap existing classes:
- Adapter: Maps an existing, incompatible class to a pre-existing target interface that the client already relies on. It makes one specific class match another specific contract.
- Facade: Defines a brand-new, high-level interface that simplifies multiple classes. It is created to provide a convenient shorthand over a complex subsystem.
Multiple specialized facades
When a subsystem grows large, a single facade risks turning into a "God Object" with hundreds of methods. The solution is creating multiple specialized facades:
OrderCheckoutFacade(cart checkout, payments, reservations)OrderReturnsFacade(reverse logistics, refund approvals, restock)OrderReportingFacade(aggregation, ledger reconciliation, analytics)
Where you've already used it
- Spring
JdbcTemplate: A classic facade over JDBC's verboseConnection,PreparedStatement,ResultSet, and checkedSQLExceptionhandling. - jQuery
$.ajax()/ Modernfetch(): High-level facade over lower-levelXMLHttpRequest, HTTP headers, MIME types, and streaming buffers. - Operating System System Calls:
open(),read(),write()act as facades over disk controllers, block drivers, cache pages, and inode metadata. - Microservice API Gateways: Acts as a network-level facade aggregating data from 10+ microservices into a single consolidated payload for mobile clients.
Pros and cons
Advantages
- Isolates Clients: Protects client code from the complexity and churn of subsystem internal classes.
- Loose Coupling: Reduces the number of dependencies between clients and subsystems.
- Promotes Layering: Establishes clear boundaries between architectural tiers (e.g. presentation vs business domain).
Disadvantages
- Risk of God Object: Can easily accumulate unrelated convenience methods if not guarded by strict domain boundaries.
- Hidden Flexibility: May conceal specialized or performance-critical subsystem configurations from advanced callers.
When not to use it
Do not introduce a Facade when a subsystem only contains one or two simple classes that are already easy to use. Wrapping a single simple service in an unnecessary facade layer adds boilerplate without reducing complexity.
Related patterns
| Pattern | Scope | Primary Objective |
|---|---|---|
| Facade | Entire subsystem | Defines a new simplified interface |
| Adapter | Single incompatible class | Bridges to an existing contract |
| Mediator | Peer components | Coordinates bidirectional communication among peers |
| Singleton | Single instance | Frequently used to implement a global Facade |
| Abstract Factory | Object creation | Can serve as a creation facade over families of objects |
Facade: order checkout coordinator
Wrap complex inventory, payment, shipping, and notification subsystems behind a unified OrderFacade with clean error handling.
Click Run tests to evaluate your solution against the behavior and structural test suite.
Interview questions
How does Facade differ from Mediator? Facade provides unidirectional abstraction over a subsystem; the subsystem classes do not know the facade exists. Mediator coordinates bidirectional peer-to-peer communication among colleague objects, with colleagues actively knowing and calling the mediator.
Does a Facade prevent clients from accessing subsystem classes directly? No. A Facade provides a convenient default path for the majority of use cases, but it does not encapsulate or hide subsystem classes from power users who need granular configuration.
When does a Facade become an anti-pattern? When it becomes a monolithic God Object that attempts to orchestrate every operation in an enterprise, violating the Single Responsibility Principle. When this happens, split it into multiple domain-focused facades.
Can a system have multiple facades over the same subsystem?
Yes. You can provide distinct facades tailored to different client personas (e.g., a CustomerFacingCheckoutFacade vs an AdminManualOrderFacade).
Try it
Ticket Booking LLD
Reserve seats with expiring holds and reconcile payment without overselling.