Java > Design Patterns in Java > Structural Patterns > Proxy Pattern
Proxy Pattern Demonstration in Java
The Proxy pattern provides a surrogate or placeholder for another object to control access to it. This example demonstrates a simple image proxy, which loads the real image only when it's actually needed. This can improve performance and reduce initial resource consumption.
Defining the Image Interface
This interface declares the common method `display()` that both the real image and the proxy will implement. It's the contract that both the `RealImage` and `ProxyImage` adhere to.
interface Image {
void display();
}
Creating the Real Image Class
The `RealImage` class represents the actual image that will be displayed. The `loadFromDisk()` method simulates the process of loading the image from a file, which could be a time-consuming operation. The constructor loads the image upon instantiation.
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk(filename);
}
@Override
public void display() {
System.out.println("Displaying " + filename);
}
private void loadFromDisk(String filename) {
System.out.println("Loading " + filename);
}
}
Implementing the Proxy Image Class
The `ProxyImage` class acts as a surrogate for the `RealImage`. It doesn't load the actual image until the `display()` method is called. This lazy loading mechanism improves performance. The `realImage` instance is only created when needed.
class ProxyImage implements Image {
private String filename;
private RealImage realImage;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
Demonstration
This code demonstrates the usage of the proxy. The `ProxyImage` is created, but the `RealImage` is not loaded until the first call to `display()`. Subsequent calls to `display()` use the already loaded `RealImage`.
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_image.jpg");
// Image will be loaded from disk only when display is called
image.display();
System.out.println("");
// Image will be displayed without loading again
image.display();
}
}
Concepts Behind the Snippet
This snippet demonstrates the Proxy pattern's core concept: controlling access to an object by providing a surrogate. The proxy can perform additional actions before or after the real object is accessed, such as lazy initialization, access control, or logging.
Real-Life Use Case
A common real-life use case is image loading in web applications. Instead of loading all images at once, which can slow down the page load time, you can use a proxy to load images only when they are visible in the viewport or when the user interacts with them.
Best Practices
Interview Tip
When discussing the Proxy pattern in an interview, emphasize its ability to provide a level of indirection and control access to an object. Explain how it can be used for lazy initialization, security, and other purposes.
When to Use Them
Use the Proxy pattern when:
Memory Footprint
The Proxy pattern can reduce the initial memory footprint by deferring the creation of the real object until it is actually needed. This is particularly useful when dealing with large objects or a large number of objects.
Alternatives
Alternatives to the Proxy pattern include:
Pros
Cons
FAQ
-
What is the difference between a Proxy and a Decorator?
A Proxy controls access to an object, while a Decorator adds behavior to an object. A Proxy has the same interface as the real object, while a Decorator can add new methods. -
When is lazy initialization useful?
Lazy initialization is useful when creating an object is expensive in terms of time or resources, and the object may not be needed immediately.