Overview:
Proxy Design Pattern is a type of structural design pattern which is used whenever we need a placeholder or representational object that can work in place of the real object.
The proxy acts as an intermediatory layer between the client and the real object and hence can control the access to the real object, add additional functionality, and even restrict client access.
Proxy is heavily used to implement lazy loading related use cases where we do not want to create full object until it is actually needed. A proxy can be used to add an additional security layer around the original object as well.
In the proxy pattern, client doesn't aware of the real class who does the functionality. Client knows only the proxy class, and sends all the requests to the proxy class. Proxy class further pass the request to the real class based on the implementation.
Source: wiki
Types:
There are four common situations in which the Proxy pattern is applicable.
Remote proxy – represent a remotely lactated object. To talk with remote objects, the client need to do additional work on communication over network. A proxy object does this communication on behalf of original object and client focuses on real talk to do.
Virtual proxy – delay the creation and initialization of expensive objects until needed, where the objects are created on demand.
Protection proxy – help to implement security over original object. They may check for access rights before method invocations and allow or deny access based on the conclusion.
Smart Proxy – performs additional housekeeping work when an object is accessed by a client.
An example can be to check if the real object is locked before it is accessed to ensure that no other object can change it.
A smart proxy interposes additional actions when an object is accessed. Typical uses include:
- Counting the number of references to the real object so that it can be freed automatically when there are no more references (smart pointer),
- Checking that the real object is locked before it is accessed to ensure that no other object can change it.
Make the RealSubject class to be thread safe,
This can be done by adding mutex locking to the methods that are not thread safe. While this may not be the most efficient way to make the underlying class thread safe, it is a useful if we cannot modify the RealSubject.
Share resources,
We could have multiple Proxy objects share the same underlying RealSubject class. This could be used to implement reference counting, for instance. This is, actually, another design pattern called the Flyweight pattern, where multiple objects share the same underlying data to minimize memory.
Example:
In corporate networks, internet access is guarded behind a network proxy. All network requests goes through proxy which first check the requests for allowed websites and posted data to network. If request looks suspicious, proxy block the request – else request pass through.
How to Implement proxy?
1. Interface class
2. Real subject class
3. Proxy class
UML Class diagram:
Interface class:
Here, we are going to create a corporate network which provides the access to the internet.
Defined the interface class here which has pure virtual function.
//Interface
class IInternet
{
public:
virtual void connectTo(string serverHost) = 0;
};
Real subject class:
This is the actual class which does the functionality of connecting to the server requested by the user. This class is derived from the interface class , and definition for the pure virtual methods from interface classes added.
//Real object
class RealInternet: public IInternet
{
public:
void connectTo(string serverHost) override
{
cout<<"RealInternet: Connecting to "<<serverHost<<endl;
}
};
Proxy class:
This is the proxy class which is also derived from the interface class. This class contains the real class object. In the constructor call, real object instance will get created.
In this example, we are going to implement the proxy class which validates the server details before it calls the real object to connect it.
This proxy class contains the list of blocked web sites by the company. When the user try to open any websites, proxy class checks whether the website is blocked by the company or not. If not blocked, then invokes real object to open the website.
class ProxyInternet: public IInternet
{
private:
//Real object instance
RealInternet* realInternet;
//list of blocked sites
vector<string> blockedSites;
void createBlockedSiteList()
{
blockedSites.push_back("google.com");
blockedSites.push_back("blog.com");
blockedSites.push_back("geeks.com");
}
public:
ProxyInternet()
{
realInternet = new RealInternet;
createBlockedSiteList();
}
void connectTo(string serverHost) override
{
bool isBlocked = false;
//check the blocked sites
for(auto siteName:blockedSites)
{
if(serverHost == siteName)
{
//site is blocked
cout<<"ProxyInternet: blocked site :"<<serverHost<<endl;
isBlocked = true;
break;
}
}
//Site is not blocked
if(false == isBlocked)
{
cout<<"ProxyInternet: Connecting to "<<serverHost<<endl;
//calling the real object to do the functionality
realInternet->connectTo(serverHost);
}
}
};
Client code:
Client knows only the proxy class, and sends all the requests to the proxy class.
void testProxyPattern()
{
//client code
IInternet* internet = new ProxyInternet;
internet->connectTo("google.com");
internet->connectTo("tutorialpoint.com");
}
Program output:
ProxyInternet: blocked site :google.com
ProxyInternet: Connecting to tutorialpoint.com
RealInternet: Connecting to tutorialpoint.com