[← Design patterns index](README.md) # Facade **Category:** Structural | **Source:** `patterns/facade/CarEngineFacade/` (+ `CarEngineFacadeRecording/`) ## Problem Using a complex subsystem directly means the client must know every class, instantiate them all, and call their methods **in the correct order**. That sequencing knowledge leaks into — and couples — every piece of business logic that touches the subsystem. ## Solution Add one class that owns the wiring and the call sequence, exposing a couple of high-level methods. The subsystem classes stay completely unaware the facade exists. A facade adds **no new functionality**; it only hides complexity, deliberately trading away some of the subsystem's generality for ease of use. ## Participants (GoF names → this repo) - **Facade** → `Facade` — knows which subsystem class handles what, and in what order. - **Subsystem classes** → `AirFlowController`, `FuelInjector`, `Starter`, `CoolingController`, `CatalyticConverter` — do the work, hold no reference to the facade. ```mermaid classDiagram class Facade { -AirFlowController _air -FuelInjector _fuel -Starter _start -CoolingController _cool -CatalyticConverter _cat +Start() +Stop() } Program --> Facade : only dependency Facade --> AirFlowController Facade --> FuelInjector Facade --> Starter Facade --> CoolingController Facade --> CatalyticConverter ``` Note every arrow points _away_ from the facade. Nothing points back — that one-directionality is what distinguishes Facade from Mediator. ## Code ```csharp // The five subsystem classes — real project has empty "// implementation" bodies public class AirFlowController { public void TakeAir() {} public void Off() {} } public class FuelInjector { public void On() {} public void Inject() {} public void Off() {} } public class Starter { public void Start() {} } public class CoolingController { public void Run() {} public void Stop() {} public void Cool() {} } public class CatalyticConverter { public void On() {} public void Off() {} } ``` ```csharp // Facade.cs — owns construction AND ordering public class Facade { private readonly AirFlowController _air = new(); private readonly CatalyticConverter _cat = new(); private readonly CoolingController _cool = new(); private readonly FuelInjector _fuel = new(); private readonly Starter _start = new(); public void Start() { _air.TakeAir(); // order matters: air before fuel before spark _fuel.On(); _fuel.Inject(); _start.Start(); _cool.Run(); _cat.On(); } public void Stop() { _fuel.Off(); // NOT the reverse of Start() — shutdown has its own order _cat.Off(); _cool.Cool(); // keep cooling after fuel is cut, then stop cooling _cool.Stop(); _air.Off(); } } ``` ```csharp // Program.cs — the file keeps the "before" version commented out for comparison // WITHOUT the facade — client owns construction AND sequencing: // var airflow = new AirFlowController(); // var fuel = new FuelInjector(); // var start = new Starter(); // var cool = new CoolingController(); // var cat = new CatalyticConverter(); // airflow.TakeAir(); fuel.On(); fuel.Inject(); start.Start(); cool.Run(); cat.On(); // fuel.Off(); cat.Off(); cool.Cool(); cool.Stop(); airflow.Off(); // WITH the facade — 11 ordered calls across 5 types collapse to 2 calls on 1 type: var facade = new Facade(); facade.Start(); facade.Stop(); ``` That the `Stop()` sequence is _not_ `Start()` reversed is the point of the whole example: the ordering is real domain knowledge, it is easy to get wrong, and it should live in exactly one place. ## Output (verified) **None** — the subsystem method bodies are deliberately empty stubs, so the program runs and exits silently. This example is about the _shape of the dependencies_, not runtime behavior. ## GoF pseudocode (video conversion library) ``` class VideoConverter is method convert(filename, format): File is file = new VideoFile(filename) sourceCodec = new CodecFactory.extract(file) if (format == "mp4") destinationCodec = new MPEG4CompressionCodec() else destinationCodec = new OggCompressionCodec() buffer = BitrateReader.read(filename, sourceCodec) result = BitrateReader.convert(buffer, destinationCodec) result = (new AudioMixer()).fix(result) return new File(result) convertor = new VideoConverter() mp4 = convertor.convert("youtubevideo.ogg", "mp4") ``` ## Applicability - You want a simple, limited interface to a complex subsystem that satisfies most clients; the few needing more can still reach past the facade. - There are many dependencies between clients and a subsystem's implementation classes. - You want to **layer** subsystems — give each layer a facade and let layers talk only through them. ## Pros / Cons | Pros | Cons | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | Isolates client code from subsystem complexity | Can grow into a god object coupled to everything | | Reduces the number of objects clients deal with; cuts compile-time dependencies | Adds an indirection layer that must be maintained | | Doesn't _prevent_ direct subsystem access when a client needs it | A facade that grows too large needs splitting into refined facades | ## Seen in the wild (.NET) - `HttpClient` over the sockets/handler/header stack. - `File.ReadAllText` over `FileStream` + `StreamReader` + encoding detection. - `WebApplication.CreateBuilder` over the hosting/DI/config subsystems. ## Related patterns - **Adapter** makes an _existing_ interface usable; Facade defines a _new_, simpler one. Adapter usually wraps one object, Facade a whole subsystem. - **Facade vs. Mediator** — both organize collaboration among many classes. Facade is **one-directional** and the subsystem doesn't know it exists; Mediator is **multi-directional** and colleagues explicitly depend on it. - **Abstract Factory** is the alternative when you only want to hide subsystem _object creation_. - A facade is often made a **Singleton**, since one instance usually suffices. --- **← Prev:** [Decorator](decorator.md) · [All patterns](README.md) · **Next →** [Mediator](mediator.md)