Design Patterns · Structural Patterns
Facade
Expose the useful operation a client needs from a complicated subsystem. Keep orchestration and lifecycle knowledge behind that interface.
This lesson follows Decorator. A facade offers a simpler interface instead of another interchangeable layer.
Facade gives clients a focused entry point to a complex subsystem. It knows the objects and call order required to complete a common task. That reduces client coupling, but the facade itself becomes coupled to those details.
Name the operation the client wants
An upload page needs a thumbnail. The media library exposes a decoder, a resizer, and an encoder. Every caller currently chooses their settings, orders their calls, and releases the decoded image. A library upgrade now touches every upload flow.
interface ImageHandle { close(): void }
interface Decoder { decode(bytes: Uint8Array): ImageHandle }
interface Resizer { resize(image: ImageHandle, width: number): void }
interface Encoder { png(image: ImageHandle): Uint8Array }
class ThumbnailFacade {
constructor(
private decoder: Decoder,
private resizer: Resizer,
private encoder: Encoder,
) {}
thumbnail(bytes: Uint8Array): Uint8Array {
const image = this.decoder.decode(bytes);
try {
this.resizer.resize(image, 160);
return this.encoder.png(image);
} finally {
image.close();
}
}
}
The subsystem interfaces are illustrative. Resize mutates the owned image, and png returns independent output bytes. The facade owns cleanup after decode succeeds. Its client does not need to know these details.
Trace the hidden orchestration
Step through
Create one thumbnail
Decode the input
The decoder returns an image handle. If decoding fails, no handle was returned for the facade to close.
Apply the common configuration
Resize uses the facade's 160-pixel preset. A separate advanced API can expose other sizes when callers need them.
Encode and release
The encoder returns PNG bytes. The finally block closes the image whether resize or encode succeeds or fails.
Try it
Change the library's resize API
upload page → update resize call
profile page → update resize call
admin importer → update resize call
Each client knows the library's details. All three need edits.
ThumbnailFacade → update resize call
thumbnail(bytes) → same client contract
The upgrade is contained if the facade can still keep its own promise.
Keep the entry point focused
Subsystem classes normally do not know the facade exists. They can still interact directly. A facade is not automatically an enforcement boundary that prevents every direct call. An architecture can impose that extra rule when useful.
One entry point can become another large subsystem
Do not collect thumbnail creation, billing, login, and email in an ApplicationFacade. Split by the operations clients actually need. The goal is less knowledge at the client boundary, not one class that knows everything.
Check yourself
Thumbnail, billing, and login operations accumulate in one facade. What is the warning?
Not quite. A facade can expose just one useful slice of a subsystem.
Correct. Focused facades keep client tasks understandable and limit change coupling.
Map the roles
| Role | In this example | Job |
|---|---|---|
| Facade | ThumbnailFacade | Gives convenient access to part of a subsystem. Knows where to direct each request and how to operate the moving parts. |
| Additional facade | for example a separate VideoPreviewFacade | Keeps unrelated features out of one facade so it does not grow into another complex structure. Clients and other facades can use it. |
| Complex subsystem | Decoder, Resizer, Encoder | Dozens of objects that need the right order and the right data to do useful work. They do not know the facade exists and still talk to each other directly. |
| Client | the upload page | Calls the facade instead of the subsystem objects |
Check yourself
Do the decoder, resizer, and encoder know that ThumbnailFacade exists?
Not quite. That would be closer to Mediator, where components know their coordinator.
Correct. The facade depends on them. They do not depend on it.
Reach for it when clients need a simple door into a complex subsystem
- you need a limited but straightforward interface to a complex subsystem. Subsystems grow more complex over time, and even well-designed ones need more setup and boilerplate. A facade gives shortcuts to the features most clients need.
- you want to structure a subsystem into layers. Give each layer a facade as its entry point, and require layers to talk to each other only through those facades. That cuts coupling between them, much like Mediator.
Check yourself
A media framework splits into an audio layer and a video layer, and you want them to talk only through narrow entry points. Which Facade use is this?
Correct. Each facade becomes the only door into its layer, which limits cross-layer coupling.
Not quite. This is about the subsystem's internal structure, not one client's convenience.
Implement it in five steps
Refactor existing code toward the pattern in this order:
- Check whether a simpler interface than the subsystem's own is possible. You are on the right track if it makes client code independent of many subsystem classes.
- Declare and implement that interface in a new facade class. The facade redirects calls from client code to the right subsystem objects.
- If client code does not already initialize the subsystem and manage its life cycle, make the facade do it.
- To get the full benefit, make all client code talk to the subsystem only through the facade. Subsystem changes, such as a library upgrade, then only touch the facade.
- If the facade grows too big, extract part of its behavior into a new, more focused facade class.
Check yourself
Half the callers still use the resizer directly after you add the facade. What do you lose?
Correct. The facade shields only the code that goes through it.
Not quite. A facade is not an enforcement boundary unless the architecture makes it one.
Name what it costs
| You gain | You pay |
|---|---|
| Your code is isolated from a complex subsystem | The facade can become a god object coupled to every class in the app |
| A reusable configuration and life cycle sequence | The simplified API exposes only selected capabilities |
| Clear boundaries between subsystem layers | The facade must track subsystem changes |
Check yourself
What is the main risk of routing every feature through one ApplicationFacade?
Correct. Split facades by the tasks clients actually need.
Not quite. Performance is not the concern. Central coupling is.
Do not confuse it with its neighbors
| Pattern | How it relates |
|---|---|
| Adapter | Facade defines a new interface for existing objects. Adapter makes an existing interface usable. Adapter usually wraps one object. Facade covers a whole subsystem. |
| Abstract Factory | When you only need to hide how the subsystem creates its objects, an abstract factory can replace a facade. |
| Flyweight | Flyweight shows how to make many small objects. Facade shows how to make one object that represents a whole subsystem. |
| Mediator | Both organize collaboration among tightly coupled classes. A facade adds no new behavior, and the subsystem does not know about it. A mediator centralizes communication, and components know only the mediator. |
| Singleton | One facade object is usually enough, so a facade is often a singleton. |
| Proxy | Both buffer a complex entity and can initialize it. A proxy has the same interface as its service, so the two are interchangeable. A facade does not. |
Check yourself
Form controls notify a coordinator, and the coordinator decides how the others react. Facade or Mediator?
Correct. With a facade, the subsystem would not know the facade exists.
Not quite. One central class is not enough. Who knows whom decides it.
Retrieve and apply
Check yourself
A thumbnail facade wraps decode, resize, and encode. Does that make the three operations atomic?
Correct. One method call hides a sequence. It does not automatically roll back effects when a later step fails.
Not quite. The shape of the interface does not establish a transaction or rollback.
Describe a facade for a library used by several callers. State its useful operation and resource owner. Continue to Flyweight to share repeated immutable state.
Source: Alexander Shvets, Dive Into Design Patterns (深入设计模式), Chinese edition v2021-1.25. Facade, printed pages 198–206. Explanations, examples, and exercises are adapted for this course.