Proxy Design Pattern
The Proxy Design Pattern is a structural design pattern.
The Proxy Design Pattern acts as a middleman between the client (user) and the actual object.
Instead of interacting directly with the original object, the client talks to the proxy, which controls access.
The proxy can:
Add extra logic before calling the original object (e.g., security checks, logging).
Add extra logic after calling the original object (e.g., caching, cleanup).
Think of it as a gatekeeper that manages how and when the original object is accessed.
Key Components:
Component | Description |
1. Subject (Interface or Abstract Class) | Defines a common interface for both the real object and the proxy. This ensures that the proxy can substitute the real object seamlessly. |
2. Real Object (RealSubject) | The actual object that performs the core operations. The proxy controls access to this object. |
3. Proxy (Proxy Class) | Acts as a middleman that controls access to the real object. It can add functionalities like logging, security, caching, or lazy initialization. |
4. Client | The part of the application that interacts with the proxy instead of directly calling the real object. |
1. Subject (Interface or Abstract Class)
package DesignPatterns.structural.proxy.atm;
public interface BankAccount {
public void deposit(double amount);
public void withdraw(double amount);
public void checkBalance();
}
2. Real Object (RealSubject)
package DesignPatterns.structural.proxy.atm;
public class RealBankAccount implements BankAccount{
private double balance;
public RealBankAccount(double initialBalance) {
this.balance = initialBalance;
}
@Override
public void deposit(double amount) {
System.out.println("Current Balance : Rupees " + balance);
this.balance+=amount;
System.out.println("Balance: " + amount + " Deposited" + " Total Balance: " + balance);
}
@Override
public void withdraw(double amount) {
if (amount <= balance) {
balance -= amount;
System.out.println("Withdrawn: Rupees" + amount + ", Remaining Balance: Rupees" + balance);
} else {
System.out.println("Insufficient funds!");
}
}
@Override
public void checkBalance() {
System.out.println("Your current balance is: Rupees" + balance);
}
}
3. Proxy (Proxy Class)
package DesignPatterns.structural.proxy.atm;
public class BankProxy implements BankAccount{
private RealBankAccount realBankAccount;
private Boolean isAuthenticated;
BankProxy(Boolean isAuthenticated, double initialBalance) {
this.isAuthenticated = isAuthenticated;
realBankAccount = new RealBankAccount(initialBalance);
}
@Override
public void withdraw(double amount) {
if (isAuthenticated) {
realBankAccount.withdraw(amount);
} else {
System.out.println("Access Denied! Please authenticate first.");
}
}
@Override
public void deposit(double amount) {
realBankAccount.deposit(amount);
}
@Override
public void checkBalance() {
if (isAuthenticated) {
realBankAccount.checkBalance();
} else {
System.out.println("Access Denied! Please authenticate first.");
}
}
}
4. Client
package DesignPatterns.structural.proxy.atm;
public class Client {
public static void main(String[] args) {
BankAccount secureAccount = new BankProxy(true, 10000);
BankAccount unsecureAccount = new BankProxy(false, 10000);
secureAccount.deposit(2000);
unsecureAccount.deposit(3000);
secureAccount.withdraw(3000);
unsecureAccount.withdraw(5000);
secureAccount.checkBalance();
unsecureAccount.checkBalance();
}
}
Pros (Advantages)
Advantage | Description |
1. Controlled Access | Proxy provides controlled access to the original object. Ideal for scenarios requiring security checks, permissions, or role-based access. |
2. Lazy Initialization (Virtual Proxy) | Proxy delays object creation until it's actually needed, improving performance. This is useful for heavy objects like images, videos, or database connections. |
3. Logging & Auditing | Proxies can log requests, responses, or user actions without modifying the original object. |
4. Performance Optimization | Proxy can act as a cache, reducing redundant operations. This is common in scenarios like database query caching or API response caching. |
5. Added Functionality | Proxies can extend functionalities like rate limiting, throttling, or load balancing without modifying the original class. |
6. Security Enhancement (Protection Proxy) | Proxies can restrict unauthorized access by adding authentication layers. |
7. Remote Access (Remote Proxy) | Useful in distributed systems where objects reside on different machines (e.g., RMI in Java). |
Cons (Disadvantages)
Disadvantage | Description |
1. Increased Complexity | Adding a proxy introduces additional classes, increasing code complexity. This can make the codebase harder to maintain. |
2. Potential Performance Overhead | While proxies can improve performance in some cases (e.g., caching), excessive proxy logic can slow down operations. |
3. Code Duplication Risk | If proxy logic overlaps with the original object’s behavior, there’s a risk of redundant code. |
4. Tight Coupling | Improper proxy implementation can lead to tight coupling between the proxy and the real object, reducing flexibility. |
5. Debugging Challenges | Since requests are routed through proxies, identifying bugs in the original object can be tricky without proper logging. |
6. May Delay Exception Handling | Since proxies control access, errors may not be thrown immediately, delaying error visibility. |
When to Use Proxy Pattern
Use when you need on-demand loading (e.g., heavy images or database connections).
Use when implementing security controls or access restrictions.
Use when adding caching, logging, or performance optimizations without modifying the original object.
Remote Proxy vs Virtual Proxy
Both are types of Proxy Design Patterns, but they serve different purposes. Here's a clear comparison:
Feature | Remote Proxy | Virtual Proxy |
Purpose | Controls access to an object located on a different machine or remote server. | Controls access to heavy objects by delaying their creation until they are actually needed. |
Focus | Focuses on communication between systems across networks. | Focuses on improving performance by implementing lazy loading. |
Example | Used in RMI (Remote Method Invocation), SOAP, gRPC, or microservices for remote calls. | Used in applications like image viewers, file explorers, or data-intensive software. |
Performance Impact | May introduce network latency due to remote communication. | Reduces memory usage and startup time by delaying object creation. |
Key Benefit | Ensures seamless communication with remote objects as if they were local. | Saves resources by creating objects only when required. |
Example Scenario | Accessing a database server, API, or cloud resource remotely. | Displaying image thumbnails instead of loading full-sized images upfront. |