Proxy design pattern for beginners.
Introduction –
Remember your school or college days? We used to proxy attendance in the classroom for our best friends, and sometimes we request our friends to proxy our presence. To manage a minimum percentage of classroom attendance.
In this proxy game, the main rule was – girls cannot proxy attendance of any their male friends, and vise-versa. Question here is why? Because the voice is different. This means to proxy someone you both should have/share the same interface.
Technically what we are achieving by proxy? We are creating an environment for our teacher. Where the teacher is feeling student X is present in the classroom. But actually/physically he/she is not present.
Now one essential concept called location transparency comes into the picture. In proxy design pattern, we achieve location transparency. Means we pretend source is here, but actually, it is not present. Proxy is acting as a source.
Till now, we understood how to make a proxy system. Of any real system for which we should have the same interface. So, we can confuse the world that users are interacting with the real system. But in-ground level, they are actually interacting with the proxy systems.
The proxy system should have a reference (or should know the address) of the real system. Because if the client asks for any service which proxy cannot provide. Then it can call the real system.
Question – what is the need for proxy?
Answer – 1. To maintain location transparency, and show caller that called node is here. In a local system. Or separate client from the server.
2. To defer the full cost of object creation and initialization until we actually need to use it.
Example –
In a distributed computing environment. Where we have client-server architecture. User feels that all execution is happening at the client end. But in real call goes to the server and business logic execution occurs at the server end.
Note:- Both client and server share the same interface to facilitate this functionality. i.e., through CORBA middleware in CPP.
There are two types of hiding –
a. Implicit hiding (Transparent hiding).
When we want to hide the target object and don’t want the caller to know that we have a hidden target object. For caller, proxy is a real object.
b. Explicit hiding.
When we want to hide the target object, and the caller knows the fact that it is not a real object, it is an indirection. We call it explicit hiding.
Types of proxy–
- Protection proxy.
- Virtual proxy.
- Remote proxy.
Protection proxy –
It controls or restrict the client to use real object by introducing proxy in between them.
Let me take a straightforward example to describe protection proxy. We all use the internet. To connect any site, we type www.XYZ.com (example for a moment), in our browser. Actually, we pass web URL to DNS and ask, please provide me the IP of the server.
Now we can do two things –
1 Provide real server IP, which may cause security issues. As a category of people, always try to hack it. It may also cause load issues as many request may come to the real server, at any point in time.
2 Have a proxy server in between. Who will help you to maintain the security; As DNS will have proxy server’s IP. Now hackers will not reach to real system. It will be helpful for load balancing point of view as well. By maintaining local cache memory for frequently asked request. Also, it can act as a load balancer. In case of many requests comes to your application, it can wakeup other servers to answer the client's demands.
Virtual proxy –
The primary purpose of the virtual proxy is to reduce/hide the object creation cost/time. What I mean here is, we will create an object only when it is required. The concept of Lazy loading is implemented through a virtual proxy. To defer the full cost of object creation and initialization until we actually need it. Creating each expensive object on demand.
Let us see two very classic example of virtual proxy –
1. Have you ever been to any e-greeting-card site? Where you can create digital greeting cards? On that site, they will show at least 20 digital greeting cards on one page. But those 20 are just thumbnail images; they are not actually digital cards. Once you click on any thumbnail image, which you are feeling is a good card, by its look, then we will create a real object of that e-card. And load that particular card on the webpage for editing purposes.
2. Suppose you require to see thousands of data in your web page. For example, exam results or emp data. We cannot load all the data at once and show. Because the screen has some size limit and loading all data at once will make the system very slow. So we can load 100 data (row) at a time, and once you scroll down after 100th data, then we can fetch/create the next 100 data and show. If the user doesn't scroll down the page, then following 100 records will never be fetched from memory.
Remote proxy –
We learned remote proxy above. When we want to have a client-server architecture but operation wise, we want the user to feel like all execution is happening at his end. Then we use a remote proxy. CORBA is a very classic example of a remote proxy.
Structure -
Now let us understand proxy design in more detail through the UML diagram.UML structure of proxy design pattern. |
Example -
Example of proxy design pattern (Click on picture to see zoom view). |
Note - From proxy, you can actually call real system or do some pre-processing and return back to client its depend upon scenario.
#include<iostream> #include<memory> // unique_ptr using namespace std; class ICalculateSum { public: virtual void printSum(int firstValue, int secondValue) = 0; }; class RealServer : public ICalculateSum { public: void printSum(int firstValue, int secondValue) { cout<< " Sum of " << firstValue << " and " << secondValue << " is => "; cout<< (firstValue + secondValue) << endl; } }; class ProxyServer : public ICalculateSum { public: ProxyServer(unique_ptr<RealServer> realServerPtr){ m_realServerPtr = move(realServerPtr); } void printSum(int firstValue, int secondValue) { cout<< "Passing control to actual server" << endl; m_realServerPtr->printSum(firstValue, secondValue); } private: unique_ptr<RealServer> m_realServerPtr; }; unique_ptr<ProxyServer> setupConnection() { unique_ptr<RealServer> realServerObj = make_unique<RealServer>(); unique_ptr<ProxyServer> ProxyServerPtr = make_unique<ProxyServer>(move(realServerObj)); return move(ProxyServerPtr); } /* ####################################################################################### ######### __ __ _ ###################################################### ######### | \/ | __ _(_)_ __ ###################################################### ######### | |\/| |/ _` | | '_ \ ###################################################### ######### | | | | (_| | | | | | ###################################################### ######### |_| |_|\__,_|_|_| |_| ###################################################### ####################################################################################### */ int main(int argc, char** argv) { unique_ptr<ProxyServer> proxyServerPtr = setupConnection(); proxyServerPtr->printSum(10,20); return 0; } ///////////////////////////////////////////////////////////////////-------------OutPut /* $ ./a.exe Passing control to actual server Sum of 10and 20is -30 */
Consequences -
It introduced a level of indirection, which will make the system slow (but flexibility will be increased).
Thanks for reading it. To learn more about design patterns and basic design principles, please see my web page.
Sure AD, I will add all basic or core design patterns (22 in numbers) soon .....
ReplyDelete