← Back to writing

The Proxy Pattern: A Software Developer's Essential Tool

Apr 25, 2025

The Proxy Pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. It’s like having a representative that acts on behalf of another object.

Proxy Pattern

The Proxy Pattern allows you to:

  • Provide a substitute or placeholder for another object
  • Control access to the original object
  • Perform operations before or after requests reach the original object

When to Use the Proxy Pattern

Use the Proxy Pattern when:

  • Lazy initialization is needed: When creating objects is expensive and you want to delay creation until absolutely necessary
  • Access control is required: When you need to restrict access to certain operations or resources based on permissions
  • Resource management is important: When working with limited resources that need controlled allocation
  • Added functionality is needed before/after access: When you want to perform operations before or after accessing the real object (like logging or caching)

The key indicator is when you need to control access to an object without changing its interface.

Structure of the Proxy Pattern

The pattern consists of these key components:

  • Subject: An interface that defines the common operations for both the RealSubject and Proxy
  • RealSubject: The actual object that the proxy represents
  • Proxy: Maintains a reference to the RealSubject and controls access to it
  • Client: Interacts with the Subject interface

Structure of the Proxy Pattern

Types of Proxies

Virtual Proxy

  • Creates expensive objects on demand (lazy initialization)
  • Example: Loading large images in a document only when they need to be displayed

Protection Proxy

  • Controls access permissions to objects
  • Example: Access control systems that verify user permissions before allowing resource access

Remote Proxy

  • Represents objects in different address spaces
  • Example: A local object representing a remote service

Smart Reference

  • Performs additional actions when objects are accessed
  • Example: Reference counting, locking mechanisms

Example: Virtual Proxy for Image Loading in C#

Problem: Loading high-resolution images is expensive and may not be immediately necessary.

Solution: Use a Virtual Proxy to load the actual image only when it needs to be displayed.

// Subject Interface
public interface IImage
{
    void Display();
}

// RealSubject
public class HighResolutionImage : IImage
{
    private string _filename;

    public HighResolutionImage(string filename)
    {
        _filename = filename;
        LoadImageFromDisk();
    }

    private void LoadImageFromDisk()
    {
        Console.WriteLine($"Loading high-resolution image: {_filename}");
        // Expensive operation: loading image data
        // In a real implementation, this might use System.Drawing or ImageSharp
        // to load and process the actual image file
    }

    public void Display()
    {
        Console.WriteLine($"Displaying high-resolution image: {_filename}");
    }
}

// Proxy
public class ImageProxy : IImage
{
    private string _filename;
    private HighResolutionImage _realImage;

    public ImageProxy(string filename)
    {
        _filename = filename;
    }

    public void Display()
    {
        // Create the real image only when Display is called
        if (_realImage == null)
        {
            _realImage = new HighResolutionImage(_filename);
        }
        _realImage.Display();
    }
}

// Client
public class Program
{
    public static void Main(string[] args)
    {
        // Using proxies for multiple images
        IImage image1 = new ImageProxy("photo1.jpg");
        IImage image2 = new ImageProxy("photo2.jpg");

        // The high-resolution image is loaded only when displayed
        Console.WriteLine("Application started...");
        Console.WriteLine("Displaying first image:");
        image1.Display();  // Only now is the first image loaded

        Console.WriteLine("Second image is not displayed, so it's never loaded");

        Console.ReadKey(); // Wait for user input before closing
    }
}

Benefits of the Proxy Pattern

  • Improved performance: Defers costly object creation until necessary
  • Enhanced security: Controls access to sensitive objects
  • Reduced complexity: Hides implementation details from clients
  • Increased flexibility: Enables features like caching, logging, and access control without changing the original object
  • Location transparency: Provides unified access to distributed objects

Limitations of the Proxy Pattern

  • Increased response time: Adds a level of indirection
  • Implementation complexity: Some proxy types can be complex to implement
  • Potential for overuse: Not every object needs a proxy

Real-World Applications

  • Web browsers: Caching proxy for web pages
  • Credit cards: Act as proxies for bank accounts

Summary

The Proxy Pattern provides a surrogate for another object to control access to it. It’s particularly useful for lazy loading, access control, and adding behavior when accessing objects. The pattern maintains the same interface as the original object while providing additional functionality.

Reference

Book: Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides. Also called the “Gang of Four” book.