Facade
Put one simple, purpose-built interface in front of a complicated subsystem so client code stops depending on its internals.
The problem
Your code has to work with a sophisticated library. That means initializing a dozen objects, remembering their dependencies, calling methods in exactly the right sequence, and handling the parts you were never interested in.
Do it once and it is tolerable. Do it in five places and your business logic is now welded to the implementation details of somebody else's framework, which will change in the next minor release.
The solution
Write a class that provides a simple interface to the complicated thing. Deliberately
limited: only the features clients genuinely need. An app that uploads short cat videos
might sit on a professional video conversion library, but all it wants is
encode(filename, format). Write that method, wire it to the library, and you have your
first facade.
The subsystem does not change, does not know, and does not care. Anyone needing the full power of the library can still reach past the facade. Most callers never will.
- 1The client makes one call with two obvious arguments. This is the whole public surface it depends on.
- 2The facade figures out the source codec. The client never learns that codecs are a thing.
- 3Format string in, codec object out. Small decisions like this are exactly what was cluttering the client.
- 4Step one of a sequence that must happen in this order. The facade owns the ordering knowledge.
- 5Step two, with the buffer from step one threaded through correctly.
- 6The easily-forgotten cleanup step, remembered once, here, for every caller forever.
- 7One call in, one file out. Swap the framework tomorrow and only this class changes.
Structure
The facade routes client requests to the right subsystem objects and manages their setup. When it starts collecting unrelated features, an additional facade splits the load, and facades may use each other. The subsystem itself is a crowd of classes that keep talking directly and remain oblivious.
Code
A video conversion framework, reduced to one honest method.
When to use it
- You want a limited but straightforward interface to a subsystem that has grown complex, often precisely because it applied a lot of other patterns and got flexible.
- You want to structure a subsystem into layers. Give each layer a facade and require layers to talk only through them; coupling drops sharply.
- You expect to replace or upgrade a third-party dependency and want the blast radius to be one file.
Pitfalls
- The god object. A facade that grows to cover everything ends up coupled to every class in the app, which is the problem you started with, relocated.
- The leaky facade. Returning raw subsystem objects re-couples the client to the internals. Return your own types or plain data.
- Facade-shaped pass-through. If every method forwards one call to one object, you have written an alias, not an abstraction.
- Hidden cost. A one-line call that starts three services and opens a socket will surprise somebody eventually. Simple to call is not the same as cheap to call.
Don't confuse it with
- Mediator. Both try to tame a crowd of tightly coupled classes. A facade simplifies access from outside and adds no new behavior, and its subsystem keeps working directly and unaware. A mediator centralizes communication so components stop knowing each other at all - they know only the mediator, and they know it deliberately.
- Adapter. An adapter makes an existing interface usable from code expecting a different one, usually wrapping a single object. A facade invents a brand new interface over an entire subsystem because the existing one is inconvenient rather than incompatible.
- Proxy. Both stand in front of something expensive and may initialize it themselves. A proxy has to share its service's interface so it can be substituted for it; a facade intentionally does not.
- Abstract Factory. If your only goal is hiding how subsystem objects get created, a factory is the lighter answer.
- Singleton. Facades are often turned into singletons since one is usually plenty. That is a lifecycle decision layered on top, not a different pattern.
Check yourself
Do the subsystem classes know that a facade exists?