Facade & Proxy Patterns
Structural patterns provide various ways to manage relationships between classes and objects. The Facade and Proxy patterns both wrap objects, but while the Facade simplifies an interface, the Proxy controls access to an object.
1. The Facade Pattern
The Problem
Large systems often consist of dozens of classes, each with its own complex API. For a client to perform a simple task, it might need to interact with many of these classes in a specific order. This couples the client code to the internal implementation details of the subsystem, making it hard to maintain and understand.
The Solution
The Facade pattern provides a simplified, higher-level interface to a complex set of classes in a subsystem. Components of the subsystem still exist and can be used directly if needed, but the Facade provides a “shortcut” for the most common use cases.
Think of it like the front desk of a hotel: you talk to the clerk (the Facade) to check in, and they handle the communication with the cleaners, the luggage handlers, and the accounting department (the Subsystem).
Java Implementation
// Subsystem Classes
class Amplifier { void on() { System.out.println("Amp on"); } }
class DvdPlayer { void play(String movie) { System.out.println("Playing " + movie); } }
class Projector { void wideScreenMode() { System.out.println("Projector in widescreen"); } }
// The Facade
class HomeTheaterFacade {
private Amplifier amp;
private DvdPlayer dvd;
private Projector projector;
public HomeTheaterFacade(Amplifier amp, DvdPlayer dvd, Projector projector) {
this.amp = amp;
this.dvd = dvd;
this.projector = projector;
}
public void watchMovie(String movie) {
System.out.println("Get ready to watch a movie...");
projector.wideScreenMode();
amp.on();
dvd.play(movie);
}
}
// Client Code
public class Main {
public static void main(String[] args) {
HomeTheaterFacade theater = new HomeTheaterFacade(new Amplifier(), new DvdPlayer(), new Projector());
theater.watchMovie("Inception");
}
}
Pros and Cons
- Pros: Reduces coupling between clients and the subsystem. Promotes the Principle of Least Knowledge (Law of Demeter).
- Cons: The Facade can become a “god object” tied to every class of an app if not carefully designed.
2. The Proxy Pattern
The Problem
Sometimes an object is “expensive” to create (like a high-resolution image or a remote database connection), or you need to control who can access certain methods, or you want to log every time a method is called. You don’t want the client to deal with these complexities directly.
The Solution
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. The Proxy implements the same interface as the original object (the “Real Subject”). When the client calls the Proxy, it can perform additional logic (like lazy initialization, access control, or logging) before or after forwarding the call to the Real Subject.
Python Example (Virtual Proxy)
from abc import ABC, abstractmethod
import time
# Subject Interface
class Image(ABC):
@abstractmethod
def display(self):
pass
# Real Subject
class RealImage(Image):
def __init__(self, filename):
self.filename = filename
self._load_from_disk()
def _load_from_disk(self):
print(f"Loading {self.filename}...")
time.sleep(2) # Simulate expensive loading
def display(self):
print(f"Displaying {self.filename}")
# Proxy
class ProxyImage(Image):
def __init__(self, filename):
self.filename = filename
self.real_image = None
def display(self):
# Lazy Initialization (Virtual Proxy)
if self.real_image is None:
self.real_image = RealImage(self.filename)
self.real_image.display()
# Usage
image = ProxyImage("high_res_photo.jpg")
# The image is NOT loaded yet
print("Proxy created. Client is doing other work...")
# Image is loaded only when display() is called
image.display()
# Second call is fast because image is already loaded
image.display()
Types of Proxies
- Virtual Proxy: Delays creation of expensive objects until they are actually needed (as shown above).
- Protection Proxy: Controls access based on permissions.
- Remote Proxy: Represents an object located in a different address space (e.g., via a network).
- Logging Proxy: Keeps a log of requests to the service.
Pros and Cons
- Pros: Allows for optimization (lazy loading), security (access control), and monitoring without changing the client or the original object.
- Cons: Can introduce latency (the proxy adds a layer) and the code might become more complicated due to many classes.