Proxy Design Pattern

The Proxy Design Pattern provides a surrogate or placeholder for another object to control access to it. This can be helpful when you need to control access to an object, add additional functionality (like logging, security checks, lazy initialization), or handle the object more efficiently.

Key Components

Subject Interface: Defines the common interface between the real object and the proxy.
Real Subject: The real object that does the actual work.
Proxy: Provides controlled access to the real subject.

Example: Bank Account Proxy

In this example, the proxy ensures that only authorized users can withdraw money from the bank account.

Step 1: Define the BankAccount interface (Subject)

interface BankAccount {
    void deposit(double amount);
    void withdraw(double amount);
    double getBalance();
}

Step 2: Implement the RealBankAccount class (Real Subject)

class RealBankAccount implements BankAccount {
    private double balance;

    public RealBankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    @Override
    public void deposit(double amount) {
        balance += amount;
        System.out.println("Deposited: " + amount + ", New Balance: " + balance);
    }

    @Override
    public void withdraw(double amount) {
        if (balance >= amount) {
            balance -= amount;
            System.out.println("Withdrew: " + amount + ", New Balance: " + balance);
        } else {
            System.out.println("Insufficient funds! Current balance: " + balance);
        }
    }

    @Override
    public double getBalance() {
        return balance;
    }
}

Step 3: Create the BankAccountProxy class (Proxy)

class BankAccountProxy implements BankAccount {
    private RealBankAccount realBankAccount;
    private String userRole;

    public BankAccountProxy(String userRole, double initialBalance) {
        this.userRole = userRole;
        this.realBankAccount = new RealBankAccount(initialBalance);
    }

    @Override
    public void deposit(double amount) {
        realBankAccount.deposit(amount);
    }

    @Override
    public void withdraw(double amount) {
        if (userRole.equals("Admin")) {
            realBankAccount.withdraw(amount);
        } else {
            System.out.println("Access denied! Only Admin can withdraw money.");
        }
    }

    @Override
    public double getBalance() {
        return realBankAccount.getBalance();
    }
}

Step 4: Client code

public class ProxyPatternExample2 {
    public static void main(String[] args) {
        BankAccount userAccount = new BankAccountProxy("User", 1000.00);
        BankAccount adminAccount = new BankAccountProxy("Admin", 1000.00);

        // User tries to deposit money (allowed)
        System.out.println("User is depositing money:");
        userAccount.deposit(200.00);

        // User tries to withdraw money (not allowed)
        System.out.println("\nUser is trying to withdraw money:");
        userAccount.withdraw(100.00);

        // Admin tries to withdraw money (allowed)
        System.out.println("\nAdmin is trying to withdraw money:");
        adminAccount.withdraw(100.00);

        // Checking balance
        System.out.println("\nAdmin's current balance: " + adminAccount.getBalance());
    }
}