Understanding the Proxy Design Pattern in Java

The Proxy Design Pattern is a structural design pattern that provides a placeholder or surrogate for another object to control access to it. A proxy can be used to add additional functionality such as lazy initialization, access control, logging, or caching before or after a request reaches the original object.

This post explains the Proxy Pattern with simple real-world examples like payment methods and ATM interactions based on the detailed tutorial.

What is the Proxy Design Pattern?

The Proxy Pattern involves a proxy object that implements the same interface as the original object and holds a reference to it. The proxy controls access, managing when or how the real object is accessed and manipulated.

Real-World Example: Payment System

When making payments, one might pay using different methods like cash, credit card, or UPI. These payment modes act as proxies to the actual cash system, adding convenience and flexibility while controlling access to real cash transactions.

Real-World Example: Bank Account and ATM

A bank account may be accessed physically or via an ATM proxy that performs authentication and validation checks before forwarding requests to the real account. The ATM acts as a proxy controlling access and adding extra steps like PIN verification.

Key Components

  • Subject Interface: Defines common operations, e.g., withdraw(), getAccountNumber().
  • Real Subject: The actual object implementing the subject interface, e.g., BankAccount.
  • Proxy: Implements the subject interface and holds a reference to a real subject, controlling access and optionally adding extra logic.

Java Code Example

// Subject Interface
public interface Account {
    void withdraw(double amount);
    String getAccountNumber();
}

// Real Subject
public class BankAccount implements Account {
    private String accountNumber;
    private double balance;

    public BankAccount(String accountNumber, double initialBalance) {
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }

    public void withdraw(double amount) {
        if(amount <= balance) {
            balance -= amount;
            System.out.println("Withdrawn: " + amount + ", Remaining balance: " + balance);
        } else {
            System.out.println("Insufficient balance");
        }
    }

    public String getAccountNumber() {
        return accountNumber;
    }
}

// Proxy
public class ATM implements Account {
    private BankAccount realAccount;
    private String pin;

    public ATM(BankAccount account, String pin) {
        this.realAccount = account;
        this.pin = pin;
    }

    private boolean authenticate(String inputPin) {
        return pin.equals(inputPin);
    }

    public void withdraw(double amount) {
        if(authenticate("1234")) { // Assume PIN is entered correctly
            realAccount.withdraw(amount);
        } else {
            System.out.println("Authentication failed");
        }
    }

    public String getAccountNumber() {
        return realAccount.getAccountNumber();
    }
}

Using the Proxy in Client Code

public class ProxyPatternDemo {
    public static void main(String[] args) {
        BankAccount account = new BankAccount("12345", 5000);
        ATM atmProxy = new ATM(account, "1234");

        atmProxy.withdraw(1000);
    }
}

Benefits of Proxy Pattern

  • Controls and manages access to the real object.
  • Supports lazy initialization for resource-heavy objects.
  • Adds extra functionalities such as logging, security, and caching.
  • Improves performance and security by controlling costly or sensitive operations.

Summary

The Proxy Design Pattern is a useful structural pattern for encapsulating access and adding extra features around an object transparently to the client. This pattern is common in resource management, security, and remote communication scenarios.

If this post helped you understand the Proxy Pattern better, please leave your questions or comments below, and follow for more Java design pattern insights.

Comments

Popular posts from this blog

Spring Boot on AWS EC2: Upload to S3 Securely Using IAM Role

Java Streams Intermediate Operations Explained with Examples

ConcurrentHashMap vs Synchronized HashMap in Java