The Facade pattern provides a simple, unified interface to a complex subsystem. Instead of making clients deal with 10 different classes, we give them one class with easy methods.
Think of it like a waiter at a restaurant. We don’t walk into the kitchen and tell the chef what temperature to cook at, tell the dishwasher which plates to use, and ask the sommelier for wine. We just tell the waiter “I’ll have the steak, medium rare.” The waiter coordinates everything behind the scenes.
The Problem It Solves
Imagine setting up a home theater. Without a facade, we’d have to:
tv.turnOn()
tv.setInput("HDMI1")
speakers.turnOn()
speakers.setVolume(30)
bluray.turnOn()
bluray.play("movie.mkv")
lights.dim(20)
Seven steps just to watch a movie. And we have to remember the exact order. If we do this from multiple places in the app, it gets messy fast.
With a facade: homeTheater.watchMovie("movie.mkv"). Done. One call.
How It Works
The facade doesn’t add new functionality. It just simplifies access to existing functionality. Clients can still use the subsystem classes directly if they need fine-grained control.
Code Implementation
# Complex subsystem classes
class TV:
def turn_on(self): print("TV: on")
def set_input(self, source): print(f"TV: input set to {source}")
def turn_off(self): print("TV: off")
class Speakers:
def turn_on(self): print("Speakers: on")
def set_volume(self, level): print(f"Speakers: volume {level}")
def turn_off(self): print("Speakers: off")
class BluRayPlayer:
def turn_on(self): print("BluRay: on")
def play(self, movie): print(f"BluRay: playing {movie}")
def stop(self): print("BluRay: stopped")
def turn_off(self): print("BluRay: off")
class Lights:
def dim(self, level): print(f"Lights: dimmed to {level}%")
def on(self): print("Lights: on full")
# Facade -- one simple interface
class HomeTheaterFacade:
def __init__(self):
self.tv = TV()
self.speakers = Speakers()
self.bluray = BluRayPlayer()
self.lights = Lights()
def watch_movie(self, movie: str):
print("--- Starting movie night ---")
self.lights.dim(20)
self.tv.turn_on()
self.tv.set_input("HDMI1")
self.speakers.turn_on()
self.speakers.set_volume(30)
self.bluray.turn_on()
self.bluray.play(movie)
def end_movie(self):
print("--- Shutting down ---")
self.bluray.stop()
self.bluray.turn_off()
self.speakers.turn_off()
self.tv.turn_off()
self.lights.on()
# One line does everything
theater = HomeTheaterFacade()
theater.watch_movie("Inception")
theater.end_movie()
// Complex subsystem classes
class TV {
turnOn() { console.log("TV: on"); }
setInput(source) { console.log(`TV: input set to ${source}`); }
turnOff() { console.log("TV: off"); }
}
class Speakers {
turnOn() { console.log("Speakers: on"); }
setVolume(level) { console.log(`Speakers: volume ${level}`); }
turnOff() { console.log("Speakers: off"); }
}
class BluRayPlayer {
turnOn() { console.log("BluRay: on"); }
play(movie) { console.log(`BluRay: playing ${movie}`); }
stop() { console.log("BluRay: stopped"); }
turnOff() { console.log("BluRay: off"); }
}
class Lights {
dim(level) { console.log(`Lights: dimmed to ${level}%`); }
on() { console.log("Lights: on full"); }
}
// Facade
class HomeTheaterFacade {
#tv = new TV();
#speakers = new Speakers();
#bluray = new BluRayPlayer();
#lights = new Lights();
watchMovie(movie) {
console.log("--- Starting movie night ---");
this.#lights.dim(20);
this.#tv.turnOn();
this.#tv.setInput("HDMI1");
this.#speakers.turnOn();
this.#speakers.setVolume(30);
this.#bluray.turnOn();
this.#bluray.play(movie);
}
endMovie() {
console.log("--- Shutting down ---");
this.#bluray.stop();
this.#bluray.turnOff();
this.#speakers.turnOff();
this.#tv.turnOff();
this.#lights.on();
}
}
const theater = new HomeTheaterFacade();
theater.watchMovie("Inception");
theater.endMovie();
// Complex subsystem classes
class TV {
void turnOn() { System.out.println("TV: on"); }
void setInput(String source) { System.out.println("TV: input set to " + source); }
void turnOff() { System.out.println("TV: off"); }
}
class Speakers {
void turnOn() { System.out.println("Speakers: on"); }
void setVolume(int level) { System.out.println("Speakers: volume " + level); }
void turnOff() { System.out.println("Speakers: off"); }
}
class BluRayPlayer {
void turnOn() { System.out.println("BluRay: on"); }
void play(String movie) { System.out.println("BluRay: playing " + movie); }
void stop() { System.out.println("BluRay: stopped"); }
void turnOff() { System.out.println("BluRay: off"); }
}
class Lights {
void dim(int level) { System.out.println("Lights: dimmed to " + level + "%"); }
void on() { System.out.println("Lights: on full"); }
}
// Facade
class HomeTheaterFacade {
private TV tv = new TV();
private Speakers speakers = new Speakers();
private BluRayPlayer bluray = new BluRayPlayer();
private Lights lights = new Lights();
void watchMovie(String movie) {
System.out.println("--- Starting movie night ---");
lights.dim(20);
tv.turnOn();
tv.setInput("HDMI1");
speakers.turnOn();
speakers.setVolume(30);
bluray.turnOn();
bluray.play(movie);
}
void endMovie() {
System.out.println("--- Shutting down ---");
bluray.stop();
bluray.turnOff();
speakers.turnOff();
tv.turnOff();
lights.on();
}
}
Real-World Examples
Facades are everywhere:
- jQuery:
$("div").hide()is a facade over complex DOM manipulation - ORM libraries:
User.findById(1)is a facade over SQL queries, connection pooling, and result mapping - AWS SDK:
s3.upload(file)is a facade over HTTP requests, multipart uploads, retries, and auth - Express.js:
res.json(data)is a facade over serialization, headers, and stream writing
Facade vs Adapter
People mix these up. Here’s the difference:
| Facade | Adapter | |
|---|---|---|
| Purpose | Simplify a complex interface | Make incompatible interfaces compatible |
| What changes | The complexity level | The interface shape |
| Number of classes wrapped | Usually many | Usually one |
When to Use
- When a subsystem has too many classes and clients need a simpler entry point
- When we want to layer our system — facade acts as a clean boundary between layers
- When we want to reduce dependencies between clients and complex subsystems
When NOT to Use
- When the subsystem is already simple — don’t add a facade over one class
- When clients genuinely need fine-grained control over every subsystem class
- When the facade becomes a God object that does everything — that’s a red flag
In simple language, a Facade is a reception desk. Behind that desk, there’s a complex office with dozens of people doing different jobs. But we don’t need to know about any of that. We just talk to the receptionist, and they handle the rest.