Proxy Pattern: Control Access and Enhance Behavior

Understand how the Proxy Pattern provides a surrogate to control access to real objects, allowing for behavior like access control, lazy loading, and logging. Includes C#/Python examples, UML, and real-world use cases.

The Proxy Pattern belongs to the structural design pattern family, which focuses on how objects are composed to form larger structures. It introduces a "surrogate" or placeholder object—called the Proxy—that stands in for a RealSubject (the actual object doing the work).

📌 Intent

The proxy controls interaction with the real object and can add new behavior without changing the real object’s code—perfect when:

  • You need access control (e.g. only admins allowed to perform certain actions)
  • You want to implement lazy loading (create the real object only when it’s actually needed)
  • You’re adding features like logging, caching, or monitoring without polluting the original class

🔍 Use Cases

Scenario Description
Remote Proxy Represents an object in another address space
Virtual Proxy Delays creation of expensive objects
Protection Proxy Controls access based on user roles
Smart Reference Proxy Adds behavior like logging, caching

📐 UML Structure

💻 Code Examples

public interface IBankAccount {
    void Withdraw(double amount);
}

public class RealBankAccount : IBankAccount {
    public void Withdraw(double amount) {
        Console.WriteLine($"Withdrew {amount} successfully.");
    }
}

public class BankAccountProxy : IBankAccount {
    private RealBankAccount _realAccount = new RealBankAccount();
    private string _role;

    public BankAccountProxy(string role) {
        _role = role;
    }

    public void Withdraw(double amount) {
        if (_role == "admin") _realAccount.Withdraw(amount);
        else Console.WriteLine("Access Denied.");
    }
}
from abc import ABC, abstractmethod

class IBankAccount(ABC):
    @abstractmethod
    def withdraw(self, amount): pass

class RealBankAccount(IBankAccount):
    def withdraw(self, amount):
        print(f"Withdrew {amount} successfully.")

class BankAccountProxy(IBankAccount):
    def __init__(self, role):
        self._real_account = RealBankAccount()
        self._role = role

    def withdraw(self, amount):
        if self._role == "admin":
            self._real_account.withdraw(amount)
        else:
            print("Access Denied.")

🌐 Real-World Examples

Lazy Loading in Entity Framework

  • What it is: A form of the Virtual Proxy.
  • How it works: Related data is represented by a proxy but not fetched from the database until needed.
  • Why it matters: Improves performance by avoiding unnecessary object creation until it's accessed.

Spring AOP Proxies

  • What it is: An example of a Smart Proxy in the Spring Framework.
  • How it works: Uses dynamic proxies to inject behavior like logging or transactions around core business logic.
  • Why it matters: Adds behavior transparently without changing the actual business classes.

Python Decorators as Smart Proxies

  • What it is: Decorators act as Smart Proxies by wrapping functions/methods.
  • How it works: A decorator intercepts a function call to insert behaviors like caching or access control.
  • Why it matters: Keeps code modular and extensible without modifying the original function.

✅ Advantages

  • Access control and behavior extension
  • Can add logging, caching without modifying the subject

⚠️ Disadvantages

  • Increased complexity
  • Too many proxies may clutter design

📊 Summary Table

Feature Proxy Pattern
Purpose Control access / add behavior
Types Remote, Virtual, Protection, Smart
Key Concept Surrogate object delegates or filters actions
UML Components Subject, RealSubject, Proxy

🧠 Quiz Preview

Test your understanding of the Proxy Pattern with our interactive quiz on TechWayFit!

🔗 Further Reading

Explore more design patterns and their applications in our Design Patterns Series.