Proxy Design Pattern
Classic GOF Structural Design Patterns
Intent
The Proxy Pattern is for interfacing with a structure, class, or some other type of object that is either large, complicated, or fragile. The intent of the proxy-pattern is to provide a placeholder or stand-in for another object to control access to it - however, it introduces an additional level of indirection. There are several reasons why you would want to do this, hence there are several uses for this pattern.
It is used to:
- Provide a placeholder for another object to control access to it - often to defer the full cost of its creation and initialization until we actually need to use it.
- Use an extra level of indirection to support distributed, controlled, or intelligent access.
- Add a wrapper and delegation to protect the real component from undue complexity.
Problem
The Proxy Pattern is primarily used when you need to support resource-intensive or slow to create objects, and do not want to instantiate such objects unless and until they are actually needed by the client.
Discussion
The Proxy Pattern provides a "stand-in" or placeholder object for another object and controls access to this other object.
In object-oriented programming, objects should always do the work they advertise through their interface (properties and methods). Any clients of these objects expect this work to be done quickly and efficiently (I certainly do expect it) - however, there are situations where an object is severely constrained and cannot live up to its responsibility. Typically this problem occurs when there is a dependency on a remote resource (resulting in network latency) or when an object takes a long time to load.
In situations like these we apply the Proxy pattern and create a proxy object that ‘stands in’ for the original object. The Proxy forwards the request to a target object. The interface of the Proxy object is the same as the original object and clients may not even be aware they are dealing with a proxy rather than the real object.
In the real world, Proxies are used all around us. One that many of us have experience with is a debit card for your banking account. The card provides all the benefits of access to the money in your account, all without having to carry all that cash around. It can be used in most places where you would use cash - only without the hassle. A debit card is merely a representational proxy of a bank account. Just like checks, your credit card acts as a proxy for your bank account and it’s a (relatively) secure way for a client (such as Amazon) to post a charge to your underlying account, without allowing that vendor direct access to the account. This kind of system is used all the time due to its simplicity and ease of use.
Structure
The structure of the Proxy is really straightforward in almost every programming language. Fundamentally, it consists of an interface that is implemented by both a real object and the proxy. Any clients making calls using the interface would have no idea whether they are actually using a proxy instead of the "real object."
In this basic diagram of the Proxy Pattern the Client communicates through an interface to a Proxy object which maintains the knowledge of the real object. The Proxy will be designed in such a way as to create the actual real object only when it is actually needed.
The structure is straightforward and consists of:
- ISubject -defines the common interface for Real Subject and the Proxy ensuring that the proxy can be used anywhere a Real Subject is expected.
- Proxy - does a number of things, including:
- provides an interface identical to Subject's so that a proxy can be substituted for for the real subject.
- controls access to the real subject and may be responsible for creating and deleting it.
- often, depending on the actual role of the proxy it can also: be responsible for encoding a request and its arguments and for sending the encoded request to the real subject in a different address space (remote proxies), cache additional information about the real subject so that they can postpone accessing it (virtual proxies), or ensures that the caller has the access permissions required to perform a request (protection proxy).
- Real Subject - represents the real object that the proxy represents.
Practical Example
For a practical example of the Proxy Pattern in a real world usage scenario, let's think back to a web browser - something that we use a lot.
First let's think about how a modern browser works (you can also see a browser example coming up in the Flyweight Pattern - modern browsers take advantage of a number of design patterns to improve performance). Browsers retrieve images from websites and display them on your browser. Not only is retrieving the images often expensive; but, the act of drawing or displaying them on the page is expensive as well. Let's assume that the browser retrieved all the images for a page. If the page is any bigger than the current display, there is really no good reason to try and show anything that is not currently visible. Why do this? It allows the browser to focus on rendering the elements on the page that it needs to and to delay rendering any images that are below the fold. At most, a browser will look at the size the image is supposed to take up and then render a blank block as a placeholder - waiting until there is an actual need to draw the image.
Much like the generic diagram in STRUCTURE above, the ProxyImage (proxy) will enable us to create a "stand-in" for the BrowserImage (real subject).
Let's expand on this practical example with some code below.
Code Samples
Below, you will find examples of the Proxy Pattern implemented in four different commonly used languages. Each one of the examples implements the exact same scenario as described in the PRACTICAL EXAMPLE section above.
Each sample will use a proxy to allow for efficiently delaying the rendering of images in a browser until they are actually needed. We will not implement the full logic for this delay - only enough to show how it could be accomplished. We will focus this set of examples on the virtual proxy implementation.
C# Proxy Code Sample
In this C# example, the Proxy pattern is used.
Java Proxy Code Sample
In this Java example, the Proxy pattern is used.
Typescript Proxy Code Sample
In this TypeScript example, the Proxy pattern is used.
JavaScript Proxy Code Sample
In this JavaScript example, the Proxy pattern is used.
Considerations
- Define an interface that will make the proxy and the original component interchangeable.
- Consider implementing a Factory that can encapsulate the decision of whether a proxy or original object should be used.
- The proxy class should hold a pointer to the real class and implements the interface.
- The pointer to the Real Subject may be initialized at construction, or on first use.
Additional Notes
- One of the advantages of Proxy pattern is security - see the DISCUSSION section above.
- This pattern delays creation of objects which might be huge size and memory intensive until they are actually needed - this in turn increases the performance of the application.
- This pattern introduces another layer of abstraction which sometimes may be an issue if the Real Subject is accessed by some of the clients directly and some of them might access the Proxy classes - possibly causing disparate behavior.
- Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.
- Decorator and Proxy have different purposes but similar structures. Both describe how to provide a level of indirection to another object, and the implementations keep a reference to the object to which they forward requests.