Provide a simplified interface to a complex subsystem, making it easier to use without exposing its internal complexity.
The Facade pattern is a structural design pattern that provides a simple, unified interface to a set of complex interfaces in a subsystem. It doesn't add new functionality — it makes an existing complex system easier to use by wrapping it with a clean, high-level API.
Think of the ignition button in a modern car. Pressing it triggers fuel injection, spark ignition, sensor checks, ECU initialization, and more. You don't need to know any of that — the button is the facade that hides it all behind a single action.
In software, this is invaluable when working with complex libraries, layered architectures, or multi-service workflows where you want to provide a clean entry point for client code.
Key Idea: Wrap a complex subsystem with a simple, focused interface. The client talks to the facade; the facade coordinates the subsystem internally.
The simplified interface. Knows which subsystem classes handle which requests and delegates client calls to the appropriate subsystem objects. It can also do additional work like ordering operations and handling errors.
The complex underlying classes that do the real work. They have no knowledge of the facade — they operate independently and can be used directly by advanced clients who need fine-grained control.
Uses only the facade instead of calling subsystem classes directly. This shields it from all the complexity and makes it much easier to swap out or upgrade the subsystem.
Without Facade, every client must understand and coordinate all subsystem classes manually — in the right order, with the right arguments:
// Client must know and coordinate everything — messy! lights.dim(20); projector.on(); projector.wideScreenMode(); sound.on(); sound.surroundSound(); sound.setVolume(60); streaming.login(); dvd.on(); dvd.play(movie); // 9 steps, easy to get wrong
// Client calls one method — clean and safe
theatre.watchMovie("Interstellar"); // That's it!Group related classes that form a logical subsystem — e.g., all classes involved in placing an order.
Define the high-level operations a client would actually want to perform. Think "actions", not "steps".
The facade's methods coordinate subsystem calls internally — handling ordering, error handling, and data passing.
Client code only imports and uses the facade class, remaining fully unaware of the underlying complexity.
Architecture
| Aspect | Facade | Adapter |
|---|---|---|
| Goal | Simplify a complex system | Make incompatible interfaces work |
| Interface | Creates a new, simpler interface | Converts one existing interface to another |
| Subsystem | Wraps many classes | Typically wraps one class |
| Problem | Too much complexity | Incompatible API |
// Facade Pattern — Home Theatre System
// ─── Complex subsystem classes ────────────────────────────────
class DVDPlayer {
public void on() { System.out.println("[DVD] Player on"); }
public void play(String m) { System.out.println("[DVD] Playing: " + m); }
public void stop() { System.out.println("[DVD] Stopped"); }
public void off() { System.out.println("[DVD] Player off"); }
}
class Projector {
public void on() { System.out.println("[Projector] On"); }
public void wideScreenMode(){ System.out.println("[Projector] Widescreen mode"); }
public void off() { System.out.println("[Projector] Off"); }
}
class SoundSystem {
public void on() { System.out.println("[Sound] System on"); }
public void setVolume(int v){ System.out.println("[Sound] Volume set to " + v); }
public void surroundSound() { System.out.println("[Sound] Surround mode on"); }
public void off() { System.out.println("[Sound] System off"); }
}
class Lights {
public void dim(int level) { System.out.println("[Lights] Dimmed to " + level + "%"); }
public void on() { System.out.println("[Lights] On"); }
}
class StreamingService {
public void login() { System.out.println("[Streaming] Logged in"); }
public void search(String m){ System.out.println("[Streaming] Found: " + m); }
}
// ─── Facade ───────────────────────────────────────────────────
// Provides a single simple interface over the complex subsystem
class HomeTheatreFacade {
private DVDPlayer dvd;
private Projector projector;
private SoundSystem sound;
private Lights lights;
private StreamingService streaming;
public HomeTheatreFacade() {
this.dvd = new DVDPlayer();
this.projector = new Projector();
this.sound = new SoundSystem();
this.lights = new Lights();
this.streaming = new StreamingService();
}
// One method replaces 8+ manual steps
public void watchMovie(String movie) {
System.out.println("\n--- Getting ready to watch: " + movie + " ---");
lights.dim(20);
projector.on();
projector.wideScreenMode();
sound.on();
sound.surroundSound();
sound.setVolume(60);
streaming.login();
streaming.search(movie);
dvd.on();
dvd.play(movie);
}
public void endMovie() {
System.out.println("\n--- Shutting down theatre ---");
dvd.stop();
dvd.off();
sound.off();
projector.off();
lights.on();
}
}
// ─── Client ───────────────────────────────────────────────────
public class Application {
public static void main(String[] args) {
HomeTheatreFacade theatre = new HomeTheatreFacade();
// One call vs 10+ individual calls
theatre.watchMovie("Interstellar");
theatre.endMovie();
}
}When a single user action (e.g., place order) requires coordinating multiple services — inventory, payment, shipping, notifications.
OrderFacade, CheckoutFacadeWhen a library has dozens of classes and you only need a small slice of its functionality — wrap it in a facade.
EmailFacade, SmsFacade, MapFacadeIn MVC or layered apps, service/facade layers expose clean methods to controllers, hiding repository and domain logic.
UserService, ProductServiceWhen building a public SDK or library — expose a simple facade API and keep your internal implementation hidden and changeable.
PaymentSDK, AuthSDKWhen modernising a legacy codebase — wrap the old messy code with a clean facade while you gradually refactor internally.
LegacyOrderFacade, OldCRMFacadeJdbcTemplate is a facade over the complex JDBC API — it hides connection management, statement creation, exception handling, and result set closing behind simple query methods.
Django's model QuerySet API is a facade — Model.objects.filter(...).order_by(...) hides SQL generation, connection pooling, and result mapping behind a clean Pythonic interface.
Custom API service classes like apiService.getUser(id) are facades over fetch or Axios — they hide base URL configuration, auth headers, error handling, and response parsing.
AWS SDK offers both low-level and high-level clients. S3Transfer is a facade over raw S3 operations, handling multipart uploads, retries, and progress tracking automatically.