Skip to content

Facade Design Pattern (Structural)

Facade is a structural design pattern that provides a simplified interface to a library, a framework, or any other complex set of classes.

Imagine that you must make your code work with a broad set of objects that belong to a sophisticated library or framework. Ordinarily, you’d need to initialize all of those objects, keep track of dependencies, execute methods in the correct order, and so on.

As a result, the business logic of your classes would become tightly coupled to the implementation details of 3rd-party classes, making it hard to comprehend and maintain.

A facade is a class that provides a simple interface to a complex subsystem which contains lots of moving parts. A facade might provide limited functionality in comparison to working with the subsystem directly. However, it includes only those features that clients really care about.

Having a facade is handy when you need to integrate your app with a sophisticated library that has dozens of features, but you need only a tiny fraction of its functionality.

For instance, an app that uploads short funny videos with cats to social media could potentially use a professional video conversion library. However, all that it really needs is a class with the single method encode(filename, format). After creating such a class and connecting it with the video conversion library, you’ll have your first facade.

When you call a shop to place a phone order, an operator is your facade to all services and departments of the shop. The operator provides you with a simple voice interface to the ordering system, payment gateways, and various delivery services.

  1. Facade provides convenient access to a particular part of the subsystem’s functionality. It knows where to direct the client’s request and how to operate all the moving parts.
  2. Additional Facade classes can be created to prevent polluting a single facade with unrelated features that might make it yet another complex structure. Additional facades can be used by both clients and other facades.
  3. Complex Subsystem consists of dozens of various objects. To make them all do something meaningful, you have to dive deep into the subsystem’s implementation details, such as initializing objects in the correct order and supplying them with data in the proper format. Subsystem classes aren’t aware of the facade’s existence. They operate within the system and work with each other directly.
  4. Client uses the facade instead of calling the subsystem objects directly.
classDiagram
    class Client {
    }
    class Facade {
        -subsystemA: SubsystemA
        -subsystemB: SubsystemB
        +operation()
    }
    class SubsystemA {
        +operationA()
    }
    class SubsystemB {
        +operationB()
    }

    Client --> Facade : calls
    Facade --> SubsystemA : coordinates
    Facade --> SubsystemB : coordinates
# These are some of the classes of a complex 3rd-party video
# conversion framework. We don't control that code, so we
# can't simplify it.
class VideoFile
class OggCompressionCodec
class MPEG4CompressionCodec
class CodecFactory
class BitrateReader
class AudioMixer
# We create a Facade class to hide the framework's complexity
# behind a simple interface. It's a trade-off between
# functionality and simplicity.
class VideoConverter:
method convert(filename, format):
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)
# Application classes don't depend on a billion classes
# provided by the complex framework. Also, if you decide to
# switch frameworks, you only need to rewrite the facade class.
class Application:
method main():
convertor = new VideoConverter()
mp4 = convertor.convert("funny-cats-video.ogg", "mp4")
mp4.save()
  • Use the Facade pattern when you need to have a limited but straightforward interface to a complex subsystem.
  • Use the Facade when you want to structure a subsystem into layers.
  1. Check whether it’s possible to provide a simpler interface than what an existing subsystem already provides. You’re on the right track if this interface makes the client code independent from many of the subsystem’s classes.
  2. Declare and implement this interface in a new facade class. The facade should redirect the calls from the client code to the appropriate objects of the subsystem. The facade should be responsible for initializing the subsystem and managing its further life cycle unless the client code already does this.
  3. To get the full benefit from the pattern, make all the client code communicate with the subsystem only via the facade. Now the client code is protected from any changes in the subsystem code.
  4. If the facade becomes too big, consider extracting part of its behavior into a new, refined facade class.

Pros:

  • You can isolate your code from the complexity of a subsystem.

Cons:

  • A facade can become a god object coupled to all classes of an app.
  • Facade defines a new interface for existing objects, whereas Adapter tries to make the existing interface usable. Adapter usually wraps just one object, while Facade works with an entire subsystem of objects.
  • Abstract Factory can serve as an alternative to Facade when you only want to hide the way the subsystem objects are created from the client code.
  • Facade is often a Singleton since a single facade object is sufficient in most cases.

// Subsystem 1
public class AudioSystem
{
public void TurnOn() => Console.WriteLine("Audio enabled");
public void SetVolume(int level) => Console.WriteLine($"Volume: {level}");
}
// Subsystem 2
public class VideoSystem
{
public void TurnOn() => Console.WriteLine("Video linked");
public void SetResolution(string res) => Console.WriteLine($"Resolution: {res}");
}
// Subsystem 3
public class Lights
{
public void Dim(int level) => Console.WriteLine($"Lights reduced to {level}%");
}
// Facade
public class HomeTheaterFacade
{
private readonly AudioSystem _audio;
private readonly VideoSystem _video;
private readonly Lights _lights;
public HomeTheaterFacade(AudioSystem audio, VideoSystem video, Lights lights)
{
_audio = audio;
_video = video;
_lights = lights;
}
public void WatchMovie()
{
Console.WriteLine("Getting ready to watch a movie...");
_lights.Dim(20);
_audio.TurnOn();
_audio.SetVolume(15);
_video.TurnOn();
_video.SetResolution("1080p");
}
}
// Usage
class Program
{
static void Main()
{
var facade = new HomeTheaterFacade(
new AudioSystem(),
new VideoSystem(),
new Lights()
);
facade.WatchMovie();
}
}