The Proxy pattern provides a surrogate or placeholder object to control access to another, different object. The Proxy object can be used in the same manner as its containing object.

A waiter serving a glass of cocktail with a mountain view in the background
Ooooh, dinner AND a view! Photo by Alev Takil / Unsplash

The Proxy object can then hide or change data on the hidden object, or otherwise manipulate its behavior. However, the Proxy must still be able to be used anywhere the hidden object is.

NOTE: This post is part of a series demonstrating software design patterns using C# and .NET.  The patterns are taken from the book Design Patterns by the Gang of Four. Check out the other posts in this series!

The Rundown

  • Type: Structural
  • Useful? 4/5 (Very)
  • Good For: Controlling access to a particular object, testing scenarios.
  • Example Code: On GitHub
exceptionnotfound/DesignPatterns
Repository for all of my Daily Design Pattern posts. - exceptionnotfound/DesignPatterns
Project for this post: Proxy

The Participants

  • The Subject defines a common interface for the RealSubject and the Proxy such that the Proxy can be used anywhere the RealSubject is expected.
  • The RealSubject defines the concrete object which the Proxy represents.
  • The Proxy maintains a reference to the RealSubject and controls access to it. It must implement the same interface as the RealSubject so that the two can be used interchangeably.

A Delicious Example

To demonstrate how to use the Proxy design pattern in real-world code, let's talk about servers in a high-end restaurant (as we did for the Facade pattern and the Adapter pattern).

A waiter at a hotel restaurant shows the daily menu

For this demo, let's imagine that servers at a restaurant primarily do three things:

  1. Take the patron's order.
  2. Deliver the patron's order.
  3. Process the patron's payment.

With these assumptions, we can create an interface IServer for these actions (this interface is the Subject participant):

/// <summary>
/// The Subject interface which both the RealSubject and proxy will need to implement
/// </summary>
public interface IServer
{
    void TakeOrder(string order);
    string DeliverOrder();
    void ProcessPayment(string payment);
}

Now let's create a real Server class (the RealSubject participant):

/// <summary>
/// The RealSubject class which the Proxy can stand in for
/// </summary>
class Server : IServer
{
    private string Order;
    public void TakeOrder(string order)
    {
        Console.WriteLine("Server takes order for " + order + ".");
        Order = order;
    }

    public string DeliverOrder()
    {
        return Order;
    }

    public void ProcessPayment(string payment)
    {
        Console.WriteLine("Payment for order (" + payment + ") processed.");
    }
}

Now imagine that our Server is an experienced server who is helping train a newly-employed server. That new employee, from the patron's perspective, is still a server and should still behave as such. However, the new trainee cannot process payments yet, as he must first learn the ropes of taking and delivering orders.

We can create a Proxy to model this new employee. The Proxy will need to maintain a reference back to the Server instance so that it can call the Server instance's ProcessPayment() method:

/// <summary>
/// The Proxy class, which can substitute for the Real Subject.
/// </summary>
class NewServerProxy : IServer
{
    private string Order;
    private Server _server = new Server();

    public void TakeOrder(string order)
    {
        Console.WriteLine("New trainee server takes order for " + order + ".");
        Order = order;
    }

    public string DeliverOrder()
    {
        return Order;
    }

    public void ProcessPayment(string payment)
    {
        Console.WriteLine("New trainee cannot process payments yet!")
        _server.ProcessPayment(payment);
    }
}

As you can see, the NewServerProxy implements its own TakeOrder() and DeliverOrder() methods, and calls the Server class's ProcessPayment() method. Since they both implement IServer, the NewServerProxy can be used any place the Server can be used.

Will I Ever Use This Pattern?

Probably. If you've ever had a need to change the behavior of an existing object without actually changing the definition of that object, the Proxy pattern can allow you to do that. Further, I can see this being very useful in testing scenarios, where you might need to replicate a class's behavior without fully implementing it.

Summary

The Proxy pattern seeks to create a "stand-in" object which can be used in place of an existing object and maintains a reference to an instance of said existing object. To fulfill the pattern, the Proxy object must be able to be used anywhere the replaced object can be used.

And, while you're here, check out our wine specials.  There's sure to be something to suit your taste.

Happy Coding!