|Pattern Name||Proxy Pattern|
|Pattern Type||Structural Pattern|
|Tagline||Provide a placeholder to control access to the original object|
|Use cases||1. When the actual object is not required in all cases, |
and a placeholder of that object can do the job in some cases
2. When caching is required for optimizing some operation of a class
3. When some extra functionality/checking is required on top of the
existing features, and the existing feature does not have any change.
In Proxy design pattern, an object represents another object. So one object works as a proxy of another object.
A proxy object represents an interface to the client. The client will not access the actual object directly, it will always use the project object in all cases.
Say, we have an object but we want to perform some additional operation/checking before using the functions of the actual object. If we follow the open-close principle, then that new operation/checking can be added to the actual object, as that will check the class implementation.
In that case, we can introduce a new class(proxy), which will implement the same interface as the original class. The proxy class will use the functionality from the actual class, it will just add the additional operation/checking in its implementation.
Take a look at different types of proxy implementations. This will give you an idea about the use-cases and also how the proxy pattern can be implemented.
Implementation of the Proxy pattern can serve multiple purposes. Based on the use cases the Proxy pattern can be of the following types:
A remote proxy is used to represent an object which is in a different address space.
While using web services, if some local object represents resources of the remote services, then that is a remote proxy. Or in the case of a remote database, if some local object represents a remote object, then it works as Remote proxy.
A remote proxy provides a local interface to the client. So the client can perform the operation/use the local object. The local object then syncs the changes to the remote object. Serialization and/or deserialization of objects can be performed while syncing the objects from local to remote or vise-versa.
Remote proxy is also called “Ambassador”.
When there is a complex or expensive object (like some image or other resources are loaded, which takes time), in that case when the client makes a request for resources initially, then provide a dummy resource and initiates a call to load the resource. When resource loading is complete then make it available for the client.
Say, a class is responsible for showing an image. The loading of an image takes time and can be shown instantly. So when the screen is loaded for the first time, then just return a dummy/placeholder for the image and then initiate the image loading process. The client will show the dummy image when loaded for the first time. Then when the actual image is available, make that available for the client.
This implementation of the Proxy pattern is called a Virtual proxy.
A protection proxy is used to control access to the actual object.
Say, there is an object which represents a user, and all user-related information is accessible in that object. But not all users should have access to all user information at a certain time. So, we can introduce a proxy class in this case. In the proxy implementation before accessing and returning the user (sensitive) information check if the client has proper permission to access the information or not.
Or, say, there is a class that performs database login access and other operations. But, not all users can perform all operations on the database. A proxy class can be introduced which will check the access before performing any database operations.
Smart reference performs additional operations when the actual object is accessed. Like, it may check if the object is locked or not, and being used by another client. or it may check the total number of object references. Any operation can be performed in case of a Smart reference.
The proxy will call a function from the actual object, in addition to that, a Smart reference proxy will perform the additional operations before or after that call.
A simple implementation of Proxy pattern will look like the diagram below.
Here are the steps you need to follow while implementing the Proxy design pattern.
- Use an interface to provide a common interface to both the actual class and proxy class.
- Implement the interface for the actual class.
- Implement the interface for the proxy class.
- In the function implementations of the proxy class, use functions from the actual class. Add any additional checking or processing or object caching in the functions if required.
- From the client use the proxy class. Do not use the actual class directly from the client.
Let’s create an interface to give the actual and proxy class a common interface. This interface is a general interface, which fulfills the need of the actual purpose of the class, and there is no rule/restriction for cleaning this interface. Here the interface is named as OperationInterface and it has a function declaration named operation().
interface OpeationInterface function operation() end interface
Here is the actual class, which implements the interface. In addition to that, there is some additional function for performing internal operations.
The constructor calls the expensive operation to initiate the expensive operation when object is created.
class ActualClass implements OperationInterface // constructor function ActualClass() someComplexExpensiveOperation(); end function function operation() // perform actual operation here end function // This is some extra function function someComplexExpensiveOperation() // perform any complex and/or expensive operation here end function end class
Proxy class implements the same interface (OperationInterface). In the operation function, it creates a new object of ActualClass if required, and then calls the operation function from the actual class object.
class ProxyClass implements OperationInterface var actualObject: ActualClass function operation() if (actualObject == null) actualObject = new ActualClass(); end if // Perform any checking or additional operation here (if required) actualObject.operation(); // Perform any checking or additional operation here (if required) end function end class
Code in the client will be like below. It will use the ProxyClass object and will never use the actual class.
var proxyObj: ProxyClass = new ProxyClass(); proxyObj.operation();