This is the 9th post in a series on design patterns.
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.
Proxy Design Pattern
Why would you want to control access to an object?
It is possible to implement a lazy initialization of that object, which is resource-intensive, or you can execute something before or after the primary logic of the class, the proxy lets you do this without changing the class. As the proxy implements the same interface as the original class, it can be passed to any client that expects a real service object.
Take a debit card as an example, which is a proxy for a bank account. By using a debit card, consumers don’t have to carry cash around. The shop owner is also happy since the money from a transaction is added to his bank account digitally.
UML Class Diagram
Not familiar with UML Class Diagram? I have written a detailed post on the UML Class diagram.
- In the absence of a pre-existing service interface, create one so that proxy and service objects can be interchanged.
- Define the proxy class. It should contain a field for storing a reference to the service. Proxy typically create and manage the entire lifecycle of their services.
- Choose the proxy methods according to their purposes. In most cases, the proxy will delegate work to the service object after doing some work.
Source Code Implementation
Check out how we can restrict access to websites based on black-listed domains using a proxy.
An Internet interface declares the interface of the service.
A class called ISPNetwork(Service) connects to the real internet in order to access the website.
In order to be able to disguise itself as a service object, ProxyInternet must follow the Internet interface. A reference field in the Proxy class points to an ISPNetwork object. It passes the request to the ISPNetwork object after the proxy has finished checking against the blacklisted domain. Usually, proxies manage the full life cycle of their service objects.
Through the same interface, the ProxyClient should work with both services and proxies. You can pass a proxy into any code that expects a service object in this way.
When To Apply Proxy Design Pattern
- Lazy Initialization (Virtual Proxy) — This occurs when a heavyweight service object wastes system resources by being always available, even if it is only occasionally needed.
- Access Control (Protection Proxy) — This is when you want to restrict access to the service object to specific clients. If the client’s credentials match the access criteria, the proxy can pass the request to the service object.
- Execution of a remote service (Remote Proxy) — This occurs when the service object is located on a remote server. The proxy handles all the nasty details of working with the network, passing the client request over the network.
- Logging requests (Logging Proxy) — When you want to keep a history of requests to a service object. A proxy can log each request before sending it to the service.
- Caching request results (Caching Proxy) — In this case, you need to cache the results of client requests and manage the lifecycle of this cache.
- Smart reference — You need to be able to dismiss a heavyweight object once no clients are using it. Clients that obtained a reference to the service object or its results can be tracked by the proxy. The proxy may periodically check if the clients are still active. The proxy might dismiss the service object if the client list is empty and free the underlying system resources.
Pros of Proxy Design Pattern
- The service object can be controlled without the clients knowing about it.
- When clients don’t care about the lifecycle of the service object, you can manage it.
- The proxy works even if the service object is not ready or not available.
- Using Open/Closed principles, you can introduce new proxies without changing the service or clients.