Proxy is a structural design pattern that lets you provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original object.
Problem #1: the object is complex, its instantiation is expensive
Solution #1:
- Delay the instantiation until the object is actually used
- If the object is never used, then the costs for its instantiation do not occur
Problem #2: the object is located on another node (i.e. on a web server), accessing the object is expensive
Solution #2:
- Instantiate and initialize a “smaller” local object, which acts as a representative (“proxy”) for the remote object
- Try to access mostly the local object
- Access the remote object only if really necessary


Structure

- The Service Interface declares the interface of the Service. The proxy must follow this interface to be able to disguise itself as a service object.
- The Service is a class that provides some useful business logic.
- The Proxy class has a reference field that points to a service object. After the proxy finishes its processing (e.g., lazy initialization, logging, access control, caching, etc.), it passes the request to the service object.
Usually, proxies manage the full lifecycle of their service objects.
- The Client should work with both services and proxies via the same interface. This way you can pass a proxy into any code that expects a service object.”
<aside>
Applicability
- Lazy initialization (virtual proxy). This is when you have a heavyweight service object that wastes system resources by being always up, even though you only need it from time to time.
- Access control (protection proxy). This is when you want only specific clients to be able to use the service object; for instance, when your objects are crucial parts of an operating system and clients are various launched applications (including malicious ones).
- Local execution of a remote service (remote proxy). This is when the service object is located on a remote server.
- Logging requests (logging proxy). This is when you want to keep a history of requests to the service object.
- Caching request results (caching proxy). This is when you need to cache results of client requests and manage the life cycle of this cache, especially if results are quite large.
- Smart reference. This is when you need to be able to dismiss a heavyweight object once there are no clients that use it.
</aside>
<aside>
How to Implement
- If there’s no pre-existing service interface, create one to make proxy and service objects interchangeable. Extracting the interface from the service class isn’t always possible, because you’d need to change all of the service’s clients to use that interface. Plan B is to make the proxy a subclass of the service class, and this way it’ll inherit the interface of the service.
- Create the proxy class. It should have a field for storing a reference to the service. Usually, proxies create and manage the whole life cycle of their services. On rare occasions, a service is passed to the proxy via a constructor by the client.
- Implement the proxy methods according to their purposes. In most cases, after doing some work, the proxy should delegate the work to the service object.
- Consider introducing a creation method that decides whether the client gets a proxy or a real service. This can be a simple static method in the proxy class or a full-blown factory method.
- Consider implementing lazy initialization for the service object.”
</aside>