Facade Pattern: Simplifying Complex Subsystems with a Unified Interface
The Facade pattern is a structural design pattern that provides a simplified interface to a complex subsystem. Instead of exposing numerous internal components directly to clients, it introduces a single entry point that encapsulates interactions with those components.
This pattern decouples the client from the subsystem by routing requests through a facade object. The facade handles the coordination, sequencing, and dependencies among internal classes, shielding the client from implementation details.
Key Characteristics
- Purpose: Offer a unified, higher-level interface to simplify usage of a complex system.
- Problem Solved: Reduces complexity for clients interacting with multiple interdependent subsystem classes.
- When to Use:
- When you need a simple interface to a complex set of classes.
- When you want to layer your system and define entry points per layer.
- When subsystems are tightly coupled and you wish to minimize direct client dependencies.
- Core Mechanism: Introduce a facade class that delegates client requests to appropriate subsystem components.
Structure
- Facade: Exposes high-level methods to the client and internally coordinates calls to subsystem classes.
- Subsystems: A collection of classes that perform specific tasks; they are unaware of the facade and operate independently.
Example: Smart Home Control System
Consider a scenario where an elderly user must manually control multiple devices—light, TV, and air conditioner. Instead of interacting with each device separately, a smart asisstant (the facade) provides voice-activated commands like "turn on all" or "turn off all."
public class Light {
public void turnOn() { System.out.println("Light on"); }
public void turnOff() { System.out.println("Light off"); }
}
public class Television {
public void turnOn() { System.out.println("TV on"); }
public void turnOff() { System.out.println("TV off"); }
}
public class AirConditioner {
public void turnOn() { System.out.println("AC on"); }
public void turnOff() { System.out.println("AC off"); }
}
public class SmartHomeFacade {
private final Light light = new Light();
private final Television tv = new Television();
private final AirConditioner ac = new AirConditioner();
public void activateAll() {
light.turnOn();
tv.turnOn();
ac.turnOn();
}
public void deactivateAll() {
light.turnOff();
tv.turnOff();
ac.turnOff();
}
public void interpretCommand(String command) {
if (command.contains("on")) activateAll();
else if (command.contains("off")) deactivateAll();
else System.out.println("Command not recognized");
}
}
// Client usage
public class Main {
public static void main(String[] args) {
SmartHomeFacade home = new SmartHomeFacade();
home.interpretCommand("turn on");
System.out.println("----------");
home.interpretCommand("turn off");
}
}
Output:
Light on
TV on
AC on
----------
Light off
TV off
AC off
Advantages
- Reduced Coupling: Clients depend only on the facade, not on individual subsystem classes.
- Simplified Interface: Hides intricate logic and sequences behind easy-to-use methods.
- Improved Maintainability: Changes within the subsysetm rarely affect client code.
- Enhanced Security: Internal components can be hidden, limiting unintended access.
Drawbacks
- Violates Open/Closed Principle: Extending functionality often requires modifying the facade itself.
- Risk of God Object: The facade may grow too large if it absorbs too much responsibility.
Real-World Application: Java Servlet API
In Apache Tomcat, the RequestFacade class implements the ServletRequest interface while wrapping an internal Request object. This facade ensures that servlets interact only with a safe, restricted view of the request, preventing direct manipulation of sensitive internal methods—a practical application of the Facade pattern aligned with the Law of Demeter.
Applicability
- Layered architectures (e.g., defining entry points for presentation, business, and data layers).
- Third-party library integrations where a simpler API is needed.
- Legacy system modernization to provide clean interfaces without refactoring core logic.