Skip to main content

Facade

complexitypopularity

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.

ApplicationVideoConverterCodecFactoryBitrateReaderAudioMixerconvert("cat.ogg", "mp4")1extract(file)2pick destination codec3read(filename, sourceCodec)4convert(buffer, destCodec)5fix(result)6return File7
  1. 1The client makes one call with two obvious arguments. This is the whole public surface it depends on.
  2. 2The facade figures out the source codec. The client never learns that codecs are a thing.
  3. 3Format string in, codec object out. Small decisions like this are exactly what was cluttering the client.
  4. 4Step one of a sequence that must happen in this order. The facade owns the ordering knowledge.
  5. 5Step two, with the buffer from step one threaded through correctly.
  6. 6The easily-forgotten cleanup step, remembered once, here, for every caller forever.
  7. 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.

Applicationmain()CLIENTVideoConverterconvert(filename, format): FileFACADECodecFactoryextract(file)SUBSYSTEMBitrateReaderread(filename, codec)convert(buffer, codec)SUBSYSTEMAudioMixerfix(result)SUBSYSTEM
usescreates

Code

A video conversion framework, reduced to one honest method.

// Business code that knows far too much about a video framework.
class Application is
method main() is
file = new VideoFile("cat.ogg")
sourceCodec = CodecFactory.extract(file)
 
if (format == "mp4")
destinationCodec = new MPEG4CompressionCodec()
else
destinationCodec = new OggCompressionCodec()
 
buffer = BitrateReader.read("cat.ogg", sourceCodec)
result = BitrateReader.convert(buffer, destinationCodec)
result = (new AudioMixer()).fix(result)
 
new File(result).save()
 
// Six framework classes referenced, one correct call order memorized,
// and this block is pasted in four other places. Upgrade the
// framework and you get to find all five.
// One class, one method, the correct order baked in.
class VideoConverter is
method convert(filename, format):File is
file = new VideoFile(filename)
sourceCodec = CodecFactory.extract(file)
destinationCodec = (format == "mp4")
? new MPEG4CompressionCodec()
: new OggCompressionCodec()
 
buffer = BitrateReader.read(filename, sourceCodec)
result = BitrateReader.convert(buffer, destinationCodec)
return new File((new AudioMixer()).fix(result))
 
// Every caller, everywhere in the app:
mp4 = new VideoConverter().convert("funny-cats-video.ogg", "mp4")
mp4.save()
// Classes from a complex third-party video framework. We do not own
// this code and cannot simplify it.
class VideoFile is
// ...
 
class OggCompressionCodec is
// ...
 
class MPEG4CompressionCodec is
// ...
 
class CodecFactory is
// ...
 
class BitrateReader is
// ...
 
class AudioMixer is
// ...
 
// The facade hides all of it behind one method. It is a deliberate
// trade of functionality for simplicity.
class VideoConverter is
method convert(filename, format):File is
file = new VideoFile(filename)
sourceCodec = 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)
 
// Application code depends on one class instead of six. Switching
// frameworks means rewriting the facade and nothing else.
class Application is
method main() is
converter = new VideoConverter()
mp4 = converter.convert("funny-cats-video.ogg", "mp4")
mp4.save()

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

Question 1 of 5

Do the subsystem classes know that a facade exists?