Structural Design Patterns
Imagine you're tasked with using a powerful, but complex, third-party library for video conversion. To convert a single file, the library requires you to perform a series of intricate steps in a specific order:
VideoFile object from the filename.AudioMixer.CompressionCodec (e.g., OggCodec, MPEG4Codec).Bitrate to configure the codec.VideoConverter to process the file.A client trying to perform a simple conversion would have to write code like this:
public class Client {
public void convertMyVideo() {
VideoFile file = new VideoFile("my_vacation.mp4");
AudioMixer audioMixer = new AudioMixer();
CompressionCodec destinationCodec = new OggCompressionCodec();
BitrateReader buffer = BitrateReader.read(file, audioMixer);
VideoConverter.convert(buffer, destinationCodec);
System.out.println("Video conversion complete!");
}
}
This is a nightmare for the client. The client code is tightly coupled to the internal complexity of the video library. It has to know about five different classes and the correct way to initialize and wire them together. If the library is ever updated and the conversion process changes, every single client that uses it would have to be rewritten.
The Facade is a structural design pattern that provides a simplified, unified interface to a larger, more complex body of code, such as a class library or a subsystem.
The goal of the Facade is to hide complexity. It wraps a complex subsystem and presents a simple, easy-to-use API to the client. The client interacts with the Facade, and the Facade delegates the calls to the appropriate objects within the subsystem.
Think of it like ordering food at a restaurant. You don't go into the kitchen to coordinate with the chef, the sous-chef, and the pantry staff. You simply give your order to a waiter (the Facade), who handles all the complex coordination for you behind the scenes.
Let's create a Facade to simplify our video conversion library.
Step 1: The Complex Subsystem
(These are the existing library classes that we can't or don't want to change.)
class VideoFile { /* ... */ }
class AudioMixer { /* ... */ }
interface CompressionCodec { /* ... */ }
class OggCompressionCodec implements CompressionCodec { /* ... */ }
class MPEG4CompressionCodec implements CompressionCodec { /* ... */ }
class BitrateReader { /* ... */ }
class VideoConverter { /* ... */ }
Step 2: The Facade Class
This class encapsulates the entire complex workflow behind one simple method.
public class VideoConversionFacade {
public File convertVideo(String fileName, String format) {
System.out.println("VideoConversionFacade: conversion started.");
VideoFile file = new VideoFile(fileName);
AudioMixer audioMixer = new AudioMixer();
CompressionCodec destinationCodec;
if (format.equals("mp4")) {
destinationCodec = new MPEG4CompressionCodec();
} else {
destinationCodec = new OggCompressionCodec();
}
BitrateReader buffer = BitrateReader.read(file, audioMixer);
File result = VideoConverter.convert(buffer, destinationCodec);
System.out.println("VideoConversionFacade: conversion completed.");
return result;
}
}
Step 3: The Simplified Client Code
The client's job is now trivial. All the complexity is hidden.
public class Client {
public void convertMyVideo() {
VideoConversionFacade converter = new VideoConversionFacade();
File convertedFile = converter.convertVideo("my_vacation.mp4", "mp4");
}
}
Benefits:
Drawbacks:
The Facade is a fundamental pattern for managing complexity and creating clean architectural boundaries.