Facade Pattern
Offer a simple entry point to several subsystem operations without absorbing all their business rules.
· Last updated: 2026-10-25 · 6 min read
Overview
Starting a movie requires lowering the screen, dimming the lights and starting the player. If every screen knows those devices and their order, the same preparation code spreads across callers.
Facade puts a simpler entry point in front of a subsystem. A caller asks to start a movie, and the facade coordinates the operations needed for that task.
UML
The caller uses MovieNight. MovieNight holds Screen, Lights and Player objects and calls them in the order needed to start or stop.
History
GoF cataloged Facade as a structural pattern in Design Patterns in 1994. It offers a higher-level interface that makes a subsystem easier to use.1
Why use it?
Callers need neither each device name nor the preparation sequence. A sequence change belongs in this entry point rather than in every screen.
A facade is an entry point, not a dumping ground. Keep business rules with their owning modules, and preserve lower-level access where callers genuinely need finer control.
Example
One method coordinates movie preparation. The device stand-ins return operation names instead of controlling hardware.
using System;
using System.Collections.Generic;
using System.Linq;
var night = new MovieNight(new Screen(), new Lights(), new Player());
Console.WriteLine(night.Start("Moon"));
// Separate an individual device operation from multi-device coordination.
sealed class Screen
{
public string Lower() => "screen down";
public string Raise() => "screen up";
}
sealed class Lights
{
public string Dim() => "lights dim";
public string Restore() => "lights normal";
}
sealed class Player
{
public string Play(string title) => "play " + title;
public string Stop() => "player stop";
}
// Keep the preparation sequence here rather than in every caller.
sealed class MovieNight(Screen screen, Lights lights, Player player)
{
public string Start(string title) =>
string.Join(" -> ", screen.Lower(), lights.Dim(), player.Play(title));
public string Stop() =>
string.Join(" -> ", player.Stop(), lights.Restore(), screen.Raise());
}
screen down -> lights dim -> play MoonThe result shows the order owned by Start(). Device behavior and coordination remain separate responsibilities.
An extended example
Add the matching stop operation and call both through the facade.
using System;
using System.Collections.Generic;
using System.Linq;
var night = new MovieNight(new Screen(), new Lights(), new Player());
Console.WriteLine(night.Start("Moon"));
Console.WriteLine(night.Stop());
// Separate an individual device operation from multi-device coordination.
sealed class Screen
{
public string Lower() => "screen down";
public string Raise() => "screen up";
}
sealed class Lights
{
public string Dim() => "lights dim";
public string Restore() => "lights normal";
}
sealed class Player
{
public string Play(string title) => "play " + title;
public string Stop() => "player stop";
}
// Keep the preparation sequence here rather than in every caller.
sealed class MovieNight(Screen screen, Lights lights, Player player)
{
public string Start(string title) =>
string.Join(" -> ", screen.Lower(), lights.Dim(), player.Play(title));
public string Stop() =>
string.Join(" -> ", player.Stop(), lights.Restore(), screen.Raise());
}
screen down -> lights dim -> play Moon
player stop -> lights normal -> screen upA single method does not make several device operations atomic. Real devices need an explicit response to partial failure. The separate Query Facade article applies this entry-point idea to assembling query results.
TypeScript example
Devices own their operations; MovieNight owns the sequence for starting and stopping a movie. Screens avoid repeating that sequence while device behavior stays with each subsystem.
// Separate an individual device operation from multi-device coordination.
class Screen {
lower(): string { return "screen down"; }
raise(): string { return "screen up"; }
}
class Lights {
dim(): string { return "lights dim"; }
restore(): string { return "lights normal"; }
}
class Player {
play(title: string): string { return "play " + title; }
stop(): string { return "player stop"; }
}
// Keep the preparation sequence here rather than in every caller.
class MovieNight {
constructor(private readonly screen: Screen, private readonly lights: Lights, private readonly player: Player) {}
start(title: string): string {
return [this.screen.lower(), this.lights.dim(), this.player.play(title)].join(" -> ");
}
stop(): string {
return [this.player.stop(), this.lights.restore(), this.screen.raise()].join(" -> ");
}
}
const night = new MovieNight(new Screen(), new Lights(), new Player());
console.log(night.start("Moon"));
console.log(night.stop());screen down -> lights dim -> play Moon
player stop -> lights normal -> screen upThe returned strings are stand-ins that show operation order. They neither control hardware nor make several operations atomic.
Related reading
Each C# example is a separate .NET 10 console program.
Compile the TypeScript examples for ES2022 or later and run the emitted JavaScript with Node.js.
Footnotes
- Gamma, Helm, Johnson, Vlissides. Design Patterns (1994). Publisher record. Structural patterns, Facade. ↩