Proxy Pattern
In the Proxy Pattern, a class represents the functionality of another class. This type of design pattern falls under structural patterns.
In the Proxy Pattern, we create an object having an original object to interface its functionality to the outer world.
Introduction
Intent: Provide a surrogate or placeholder for another object to control access to it.
Main Problem: Issues arise when accessing an object directly, for example, the object is on a remote machine. In object-oriented systems, some objects are problematic to access directly due to various reasons (like high creation costs, security controls needed, or out-of-process access), which can cause issues for users or system architecture. We can add a layer for accessing such objects.
When to Use: Want to control access to an object.
How to Solve: Add an intermediary layer.
Key Code: Implement with the proxy class.
Examples: 1. Windows shortcuts.
- Pigsy looking for Gao Cuilan, but it was Sun Wukong in disguise. Sun Wukong is a proxy for Gao Cuilan.
- Buying train tickets not necessarily at the station but at a ticket agency.
- A check or bank draft is a proxy for funds in an account.
- Spring AOP.
Advantages: 1. Clear responsibilities.
- High scalability.
- Smartness.
Disadvantages: 1. Slower processing speeds due to the proxy layer.
- Complex implementation in some cases.
Usage Scenarios: 1. Remote proxy.
- Virtual proxy.
- Copy-on-Write proxy.
- Protection proxy.
- Cache proxy.
- Firewall proxy.
- Synchronization proxy.
- Smart reference proxy.
Notes: 1. Unlike the Adapter pattern, which changes the interface, the Proxy pattern does not change the interface of the proxied class.
- Unlike the Decorator pattern, which enhances functionality, the Proxy pattern controls access.
Implementation
We will create an Image interface and concrete classes implementing the Image interface. ProxyImage is a proxy class to reduce memory footprint of RealImage object loading.
ProxyPatternDemo class uses ProxyImage to get an Image object to load and display as needed.
Step 1
Create an interface.
Image.java
public interface Image {
void display();
}
Step 2
Create concrete classes implementing the interface.
RealImage.java
public 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);
}
}
ProxyImage.java
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
Step 3
Use ProxyImage to get RealImage class object when required.
ProxyPatternDemo.java
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// Image will be loaded from disk
image.display();
System.out.println("");
// Image will not be loaded from disk
image.display();
}
}
Step 4
Execute the program, output:
Loading test_10mb.jpg
Displaying test_10mb.jpg
Displaying test_10mb.jpg