Proxy Pattern – Head First Approach
The Proxy Pattern is a structural design pattern that provides a placeholder or surrogate object to control access to another object, adding a level of indirection. This pattern is particularly useful for managing resource-intensive objects or for adding security controls.
What is the Proxy Pattern?
Definition: The Proxy Pattern provides a surrogate or placeholder for another object to control access to it. Proxies are often used to lazy-load resources, log requests, or manage permissions.
By acting as an intermediary, the proxy can control the interaction with the actual object, either by deferring the action or adding additional functionality such as access control or caching.
Problem Scenario
Imagine you are building an application that loads large images from a remote server. Instead of loading these images directly, which could take time and bandwidth, you can use a proxy to display a placeholder while the actual image is fetched in the background. This improves the user experience by providing a faster initial response.
Another scenario could involve controlling access to sensitive objects. For example, you may want to ensure that only authorized users can invoke certain methods on an object. The proxy would handle these security checks.
Using the Proxy Pattern
Let’s explore how to implement the Proxy Pattern using examples from the Head First Design Patterns book.
Step 1: Define the Subject Interface
The subject interface defines the common operations for both the real object and the proxy.
public interface Image {
void display();
}
Step 2: Create the Real Subject Class
This class contains the actual logic for the object we want to control access to. For example, loading and displaying an image from a remote server.
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("Loading " + filename);
}
public void display() {
System.out.println("Displaying " + filename);
}
}
Step 3: Implement the Proxy Class
The proxy class controls access to the RealImage
class. It will only load the image when it’s necessary to display it.
public class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
Step 4: Client Code
The client interacts with the proxy instead of the real object, but from their perspective, the functionality remains the same.
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_image.jpg");
// Image will be loaded from disk
image.display();
// Image will not be loaded from disk, as it's already cached
image.display();
}
}
Output:
Loading test_image.jpg
Displaying test_image.jpg
Displaying test_image.jpg
In this example, the ProxyImage
class acts as a placeholder. The RealImage
object is only loaded the first time the display()
method is called. Subsequent calls to display()
use the cached image, avoiding the need to reload the image from the disk.
Expanding the Proxy Pattern
Types of Proxies
Virtual Proxy: This proxy manages the creation and initialization of a resource that is expensive to instantiate, such as large images or data-heavy resources.
Protection Proxy: This type of proxy controls access to the original object based on permissions. It is commonly used in applications requiring authentication and authorization.
Remote Proxy: This proxy represents an object that resides in a different address space (e.g., on a remote server). It communicates over a network to interact with the real object.
When to Use the Proxy Pattern
Lazy Loading: When you want to defer the initialization of an expensive object until it’s needed.
Access Control: To add security checks, such as validating user permissions before allowing access to certain methods.
Remote Access: When the actual object is located on a remote server, the proxy can act as a local representative.
Logging and Monitoring: You can add logging, monitoring, or analytics by having the proxy intercept the calls to the real object.
Bullet Points
The Proxy Pattern provides a surrogate object that controls access to the real object.
It is useful for adding functionality such as lazy initialization, access control, or logging.
Proxies can be used for different purposes, such as virtual proxies for expensive objects or protection proxies for managing permissions.
Conclusion
The Proxy Pattern offers a convenient way to manage resource-intensive objects and control access to them. By decoupling the client from the real object, you gain flexibility in how and when resources are used. It’s a powerful design pattern for improving efficiency and adding control in complex systems.
Subscribe to my newsletter
Read articles from Alyaa Talaat directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Alyaa Talaat
Alyaa Talaat
As a continuous learner, I’m always exploring new technologies and best practices to enhance my skills in software development. I enjoy tackling complex coding challenges, whether it's optimizing performance, implementing new features, or debugging intricate issues.