Facade
Facade hides a tangle of interacting classes behind one clean entry point, so client code issues a single high-level call instead of orchestrating the subsystem itself.
Problem
Suppose your app lets users watch a movie at the press of a button. Behind the scenes, that means dimming the lights, powering on the projector and switching it to widescreen mode, powering on the amplifier and setting its volume, and powering on the DVD player before telling it to play - five objects, each with its own methods, called in a specific order that the client code has to get exactly right.
If that setup logic lives directly in the client, every place that wants to watch a movie duplicates the same multi-step sequence - and stopping a movie needs its own mirrored sequence to power everything down in the right order. Miss a step or get the order wrong, and the amplifier blasts at full volume into a bright room, or the DVD player tries to play before the projector is even on.
Solution
Introduce one class - the facade - that sits in front of the subsystem and exposes only the operations clients actually need, such as `exportVideo(format)`. Internally, the facade owns the job of creating subsystem objects, wiring their dependencies, and calling them in the correct order.
Clients no longer see the codec manager, bitrate reader, or mixer at all - they see one method call. Direct access to the subsystem still exists for cases that need fine-grained control; the facade is an added convenience layer, not a wall.
When to Use
- Your code only needs a handful of operations from a large, intricate library or subsystem, and you'd rather not learn or expose its full surface.
- You want a clear seam between architectural layers, with each layer talking to the next only through a defined entry point.
- You're integrating a third-party framework and want to keep its API from leaking into scattered parts of your application.
Real-World Examples
- **jQuery** - collapses inconsistent, verbose cross-browser DOM APIs into a handful of chainable calls like `$(el).hide()`, hiding browser-specific quirks entirely.
- **Django's `Model.objects`** - a facade over SQL connection handling, query building, and row-to-object mapping, letting `User.objects.filter(...)` stand in for dozens of lower-level steps.
- **Stripe's SDK `charge()` call** - hides HTTP request construction, authentication headers, retries, and error mapping behind a single method for the merchant's application.
Structure
A single Facade class exposes a narrow, task-oriented API. Behind it sit the Complex Subsystem classes, which do the real work but require careful setup and sequencing. The Facade translates each simple client call into the right sequence of subsystem calls.
Participants
Exposes a small set of high-level operations and holds the knowledge of which subsystem objects to create, configure, and call in what order to fulfill each one.
In the diagram: Facade.
The collection of classes doing the actual work - codecs, mixers, readers, and the like. These classes have no notion that a facade exists and can be used with or without it.
In the diagram: Amplifier, Projector, DVD Player, Lights.
Calls the facade's simplified methods instead of assembling subsystem objects itself, staying insulated from internal wiring and sequencing details.
In the diagram: Client.
class Amplifier {
on() { console.log('Amplifier: powering on'); }
setVolume(level) { console.log(`Amplifier: setting volume to ${level}`); }
off() { console.log('Amplifier: powering off'); }
}
class Projector {
on() { console.log('Projector: powering on'); }
wideScreenMode() { console.log('Projector: switching to widescreen mode'); }
off() { console.log('Projector: powering off'); }
}
class DVDPlayer {
on() { console.log('DVD Player: powering on'); }
play(movie) { console.log(`DVD Player: playing "${movie}"`); }
off() { console.log('DVD Player: powering off'); }
}
class Lights {
dim(level) { console.log(`Lights: dimming to ${level}%`); }
on() { console.log('Lights: turning on'); }
}
class HomeTheaterFacade {
#amplifier;
#projector;
#dvdPlayer;
#lights;
constructor() {
this.#amplifier = new Amplifier();
this.#projector = new Projector();
this.#dvdPlayer = new DVDPlayer();
this.#lights = new Lights();
}
watchMovie(movie) {
this.#lights.dim(10);
this.#projector.on();
this.#projector.wideScreenMode();
this.#amplifier.on();
this.#amplifier.setVolume(5);
this.#dvdPlayer.on();
this.#dvdPlayer.play(movie);
console.log('Enjoy the movie!');
}
endMovie() {
this.#dvdPlayer.off();
this.#amplifier.off();
this.#projector.off();
this.#lights.on();
console.log('Home theater shut down.');
}
}
const homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie('Interstellar');
Step 1 of 5
Four subsystem classes, each with its own API
`Amplifier`, `Projector`, `DVDPlayer`, and `Lights` each expose different method names (`setVolume`, `wideScreenMode`, `play`, `dim`) - none of them know about each other.
Step 2 of 5
HomeTheaterFacade holds references to every subsystem
The constructor creates and stores all four subsystem instances in private fields (`#amplifier`, `#projector`, `#dvdPlayer`, `#lights`) - the client will never construct these directly.
Step 3 of 5
watchMovie() sequences seven subsystem calls into one step
Dimming lights, powering the projector, switching to widescreen, powering the amp, setting volume, powering the DVD player, and playing the movie all happen inside one method - the client calls it once instead of coordinating four objects.
Step 4 of 5
endMovie() encapsulates the reverse sequence
Shutdown order is different from startup order (DVD off, then amp, then projector, then lights on) - the facade hides that ordering knowledge from the client entirely.
Step 5 of 5
The client only ever talks to the facade
`homeTheater.watchMovie('Interstellar')` is the entire client-side interaction - no `Amplifier`, `Projector`, `DVDPlayer`, or `Lights` object appears in the client code at all.
class Amplifier {
public on(): void { console.log('Amplifier: powering on'); }
public setVolume(level: number): void { console.log(`Amplifier: setting volume to ${level}`); }
public off(): void { console.log('Amplifier: powering off'); }
}
class Projector {
public on(): void { console.log('Projector: powering on'); }
public wideScreenMode(): void { console.log('Projector: switching to widescreen mode'); }
public off(): void { console.log('Projector: powering off'); }
}
class DVDPlayer {
public on(): void { console.log('DVD Player: powering on'); }
public play(movie: string): void { console.log(`DVD Player: playing "${movie}"`); }
public off(): void { console.log('DVD Player: powering off'); }
}
class Lights {
public dim(level: number): void { console.log(`Lights: dimming to ${level}%`); }
public on(): void { console.log('Lights: turning on'); }
}
class HomeTheaterFacade {
private amplifier: Amplifier;
private projector: Projector;
private dvdPlayer: DVDPlayer;
private lights: Lights;
constructor() {
this.amplifier = new Amplifier();
this.projector = new Projector();
this.dvdPlayer = new DVDPlayer();
this.lights = new Lights();
}
public watchMovie(movie: string): void {
this.lights.dim(10);
this.projector.on();
this.projector.wideScreenMode();
this.amplifier.on();
this.amplifier.setVolume(5);
this.dvdPlayer.on();
this.dvdPlayer.play(movie);
console.log('Enjoy the movie!');
}
public endMovie(): void {
this.dvdPlayer.off();
this.amplifier.off();
this.projector.off();
this.lights.on();
console.log('Home theater shut down.');
}
}
const homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie('Interstellar');
class Amplifier {
public void on() { System.out.println("Amplifier: powering on"); }
public void setVolume(int level) { System.out.println("Amplifier: setting volume to " + level); }
public void off() { System.out.println("Amplifier: powering off"); }
}
class Projector {
public void on() { System.out.println("Projector: powering on"); }
public void wideScreenMode() { System.out.println("Projector: switching to widescreen mode"); }
public void off() { System.out.println("Projector: powering off"); }
}
class DVDPlayer {
public void on() { System.out.println("DVD Player: powering on"); }
public void play(String movie) { System.out.println("DVD Player: playing \"" + movie + "\""); }
public void off() { System.out.println("DVD Player: powering off"); }
}
class Lights {
public void dim(int level) { System.out.println("Lights: dimming to " + level + "%"); }
public void on() { System.out.println("Lights: turning on"); }
}
class HomeTheaterFacade {
private final Amplifier amplifier = new Amplifier();
private final Projector projector = new Projector();
private final DVDPlayer dvdPlayer = new DVDPlayer();
private final Lights lights = new Lights();
public void watchMovie(String movie) {
lights.dim(10);
projector.on();
projector.wideScreenMode();
amplifier.on();
amplifier.setVolume(5);
dvdPlayer.on();
dvdPlayer.play(movie);
System.out.println("Enjoy the movie!");
}
public void endMovie() {
dvdPlayer.off();
amplifier.off();
projector.off();
lights.on();
System.out.println("Home theater shut down.");
}
}
HomeTheaterFacade homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie("Interstellar");
class Amplifier
{
public void On() => Console.WriteLine("Amplifier: powering on");
public void SetVolume(int level) => Console.WriteLine($"Amplifier: setting volume to {level}");
public void Off() => Console.WriteLine("Amplifier: powering off");
}
class Projector
{
public void On() => Console.WriteLine("Projector: powering on");
public void WideScreenMode() => Console.WriteLine("Projector: switching to widescreen mode");
public void Off() => Console.WriteLine("Projector: powering off");
}
class DVDPlayer
{
public void On() => Console.WriteLine("DVD Player: powering on");
public void Play(string movie) => Console.WriteLine($"DVD Player: playing \"{movie}\"");
public void Off() => Console.WriteLine("DVD Player: powering off");
}
class Lights
{
public void Dim(int level) => Console.WriteLine($"Lights: dimming to {level}%");
public void On() => Console.WriteLine("Lights: turning on");
}
class HomeTheaterFacade
{
private readonly Amplifier _amplifier = new();
private readonly Projector _projector = new();
private readonly DVDPlayer _dvdPlayer = new();
private readonly Lights _lights = new();
public void WatchMovie(string movie)
{
_lights.Dim(10);
_projector.On();
_projector.WideScreenMode();
_amplifier.On();
_amplifier.SetVolume(5);
_dvdPlayer.On();
_dvdPlayer.Play(movie);
Console.WriteLine("Enjoy the movie!");
}
public void EndMovie()
{
_dvdPlayer.Off();
_amplifier.Off();
_projector.Off();
_lights.On();
Console.WriteLine("Home theater shut down.");
}
}
var homeTheater = new HomeTheaterFacade();
homeTheater.WatchMovie("Interstellar");
class Amplifier:
def on(self) -> None:
print("Amplifier: powering on")
def set_volume(self, level: int) -> None:
print(f"Amplifier: setting volume to {level}")
def off(self) -> None:
print("Amplifier: powering off")
class Projector:
def on(self) -> None:
print("Projector: powering on")
def wide_screen_mode(self) -> None:
print("Projector: switching to widescreen mode")
def off(self) -> None:
print("Projector: powering off")
class DVDPlayer:
def on(self) -> None:
print("DVD Player: powering on")
def play(self, movie: str) -> None:
print(f'DVD Player: playing "{movie}"')
def off(self) -> None:
print("DVD Player: powering off")
class Lights:
def dim(self, level: int) -> None:
print(f"Lights: dimming to {level}%")
def on(self) -> None:
print("Lights: turning on")
class HomeTheaterFacade:
def __init__(self) -> None:
self._amplifier = Amplifier()
self._projector = Projector()
self._dvd_player = DVDPlayer()
self._lights = Lights()
def watch_movie(self, movie: str) -> None:
self._lights.dim(10)
self._projector.on()
self._projector.wide_screen_mode()
self._amplifier.on()
self._amplifier.set_volume(5)
self._dvd_player.on()
self._dvd_player.play(movie)
print("Enjoy the movie!")
def end_movie(self) -> None:
self._dvd_player.off()
self._amplifier.off()
self._projector.off()
self._lights.on()
print("Home theater shut down.")
home_theater = HomeTheaterFacade()
home_theater.watch_movie("Interstellar")
Step 1 of 5
Four subsystem classes, each with its own API
`Amplifier`, `Projector`, `DVDPlayer`, and `Lights` each expose different method names (`set_volume`, `wide_screen_mode`, `play`, `dim`) - none of them know about each other.
Step 2 of 5
HomeTheaterFacade holds references to every subsystem
`__init__` creates and stores all four subsystem instances (`self._amplifier`, `self._projector`, `self._dvd_player`, `self._lights`) - the client never constructs these directly.
Step 3 of 5
watch_movie() sequences seven subsystem calls into one step
Dimming lights, powering the projector, switching to widescreen, powering the amp, setting volume, powering the DVD player, and playing the movie all happen inside one method call.
Step 4 of 5
end_movie() encapsulates the reverse sequence
Shutdown order (DVD off, amp off, projector off, then lights on) differs from startup order - the facade hides that ordering knowledge from the client.
Step 5 of 5
The client only ever talks to the facade
`home_theater.watch_movie("Interstellar")` is the entire client-side interaction - no `Amplifier`, `Projector`, `DVDPlayer`, or `Lights` object appears in the client code.
Click "Run" to execute this code in a sandboxed frame and see console output here.
TypeScript runs as plain JavaScript here - type annotations are stripped, not type-checked.
Click "Run" to execute this code in a sandboxed frame and see console output here.
Advantages
- Application code reads at the level of business intent ("export the video") instead of being cluttered with subsystem plumbing.
- The subsystem can be refactored, upgraded, or replaced with fewer ripple effects, since only the facade needs to track its API surface.
- Large subsystems can be split into layers, each fronted by its own facade, giving a clear entry point per layer instead of one tangled dependency graph.
Disadvantages
- Left unchecked, a facade tends to accumulate responsibilities for every subsystem in the app and turns into a god object that everything depends on.
- Advanced use cases that need fine-grained control over the subsystem may find the facade's simplified surface too restrictive and end up bypassing it anyway.
Question 1 of 10
In the home-theater example, why does watching a movie require getting five objects' calls in the right order?
Correct! Watching a movie means dimming the lights, powering on the projector and setting widescreen mode, powering on the amplifier and setting volume, and powering on the DVD player before playing - five objects, each with its own methods, called in a specific order.
Not quite. Watching a movie means dimming the lights, powering on the projector and setting widescreen mode, powering on the amplifier and setting volume, and powering on the DVD player before playing - five objects, each with its own methods, called in a specific order.
Question 2 of 10
In the home-theater example, what does the client call instead of five separate device methods?
Correct! The client just calls watchMovie() on the HomeTheaterFacade - dimming the lights, powering the projector and amplifier, and starting the DVD player all happen behind that one call, in the right order, every time.
Not quite. The client just calls watchMovie() on the HomeTheaterFacade - dimming the lights, powering the projector and amplifier, and starting the DVD player all happen behind that one call, in the right order, every time.
Question 3 of 10
Does introducing a facade remove direct access to the subsystem entirely?
Correct! Direct access to the subsystem still exists for cases that need fine-grained control; the facade is an added convenience layer, not a wall.
Not quite. Direct access to the subsystem still exists for cases that need fine-grained control; the facade is an added convenience layer, not a wall.
Question 4 of 10
In the solution, what is the facade responsible for internally?
Correct! Internally, the facade owns the job of creating subsystem objects, wiring their dependencies, and calling them in the correct order, exposing only the operations clients actually need.
Not quite. Internally, the facade owns the job of creating subsystem objects, wiring their dependencies, and calling them in the correct order, exposing only the operations clients actually need.
Question 5 of 10
In the sample implementation, what does HomeTheaterFacade's constructor do?
Correct! The constructor creates and stores all four subsystem instances in private fields, so the client will never construct the Amplifier, Projector, DVDPlayer, or Lights directly.
Not quite. The constructor creates and stores all four subsystem instances in private fields, so the client will never construct the Amplifier, Projector, DVDPlayer, or Lights directly.
Question 6 of 10
According to the pros, what happens to application code once it talks to a facade instead of the subsystem directly?
Correct! Application code reads at the level of business intent ("export the video") instead of being cluttered with subsystem plumbing, since the facade absorbs the wiring details.
Not quite. Application code reads at the level of business intent ("export the video") instead of being cluttered with subsystem plumbing, since the facade absorbs the wiring details.
Question 7 of 10
Why does endMovie() need its own separate sequence rather than just calling watchMovie()'s steps in reverse order?
Correct! Shutdown order is different from startup order (DVD off, then amp, then projector, then lights on) - the facade hides that ordering knowledge from the client entirely by encapsulating it in its own method.
Not quite. Shutdown order is different from startup order (DVD off, then amp, then projector, then lights on) - the facade hides that ordering knowledge from the client entirely by encapsulating it in its own method.
Question 8 of 10
What goes wrong if the multi-step setup logic lives directly in client code instead of behind a facade?
Correct! Every place that wants to watch a movie duplicates the same multi-step sequence, and stopping a movie needs its own mirrored teardown - miss a step or get the order wrong, and the amplifier or DVD player misbehaves.
Not quite. Every place that wants to watch a movie duplicates the same multi-step sequence, and stopping a movie needs its own mirrored teardown - miss a step or get the order wrong, and the amplifier or DVD player misbehaves.
Question 9 of 10
In the Facade structure, what do the Complex Subsystem classes know about the Facade?
Correct! The Complex Subsystem classes do the actual work and have no notion that a facade exists, so they can be used with or without it.
Not quite. The Complex Subsystem classes do the actual work and have no notion that a facade exists, so they can be used with or without it.
Question 10 of 10
What tradeoff does the pattern warn about if a facade is left unchecked over time?
Correct! Left unchecked, a facade tends to accumulate responsibilities for every subsystem in the app and turns into a god object that everything depends on.
Not quite. Left unchecked, a facade tends to accumulate responsibilities for every subsystem in the app and turns into a god object that everything depends on.