Skip to content

Facade

Facade provides a single, unified interface to a set of interfaces in a subsystem, giving clients one easy entry point instead of forcing them to orchestrate many collaborating classes themselves.

A capable subsystem often has a lot of moving parts. To convert a video file you might need a decoder, an audio mixer, a codec selector, a bitrate calculator, and a writer — each with its own setup, ordering rules, and quirks. A client that just wants “turn this file into MP4” should not have to learn all five classes, instantiate them in the right order, and wire their outputs together. That knowledge leaks the subsystem’s internals into every caller and makes the subsystem painful to change.

Facade is a single class that knows the dance. It exposes a small, task-oriented method — convert(file, format) — and internally creates and coordinates the subsystem objects in the right sequence. Clients depend only on the facade. The subsystem classes stay fully usable for advanced callers who need them directly, but the common case becomes one call. Refactor the subsystem and you fix one facade, not a hundred call sites.

classDiagram
  class Client
  class VideoConverter {
    +convert(file, format) string
  }
  class Decoder {
    +decode(file) string
  }
  class AudioMixer {
    +mix(stream) string
  }
  class Encoder {
    +encode(stream, format) string
  }
  Client --> VideoConverter : uses
  VideoConverter --> Decoder
  VideoConverter --> AudioMixer
  VideoConverter --> Encoder
A facade fronts several subsystem classes behind one method
  • Facade (VideoConverter) — the single class clients talk to; it knows how to coordinate the subsystem.
  • Subsystem classes (Decoder, AudioMixer, Encoder) — the real workers; they know nothing of the facade and can still be used directly.
  • Client — calls the facade and stays insulated from the subsystem’s structure.

A VideoConverter facade turns a one-line request into the right sequence of decode, mix, and encode calls.

class Decoder {
decode = (file: string) => `raw(${file})`;
}
class AudioMixer {
mix = (stream: string) => `mixed(${stream})`;
}
class Encoder {
encode = (stream: string, format: string) => `${stream}.${format}`;
}
// Facade: one method hides the subsystem choreography.
class VideoConverter {
private decoder = new Decoder();
private mixer = new AudioMixer();
private encoder = new Encoder();
convert(file: string, format: string): string {
const raw = this.decoder.decode(file);
const mixed = this.mixer.mix(raw);
return this.encoder.encode(mixed, format);
}
}
const converter = new VideoConverter();
console.log(converter.convert('clip.avi', 'mp4')); // mixed(raw(clip.avi)).mp4
  • Pro: shrinks a multi-class subsystem to one easy entry point for the common case.
  • Pro: decouples clients from subsystem internals, so the subsystem can be refactored freely.
  • Pro: advanced callers can still reach the subsystem directly; the facade is optional, not a wall.
  • Con: a facade can drift into a god object that knows too much if you keep piling features onto it.
  • Con: it may hide useful flexibility, tempting clients to accept the easy path when they need the detailed one.
  • Adapter changes one object’s interface to match an expected one; Facade invents a brand-new simpler interface over many objects.
  • Abstract Factory can sit behind a facade to create the subsystem objects the facade coordinates.
What does a Facade provide?
Do the subsystem classes know about the facade?
How does Facade differ from Adapter?
What is a risk of overusing a Facade?