This tutorial is a C++ implementation of Proxy design pattern. In this brief example we will discuss the Proxy pattern, the need for it as well as how to go about implementing it. As usual, I will first start with the WHY and then the HOW of the Proxy design pattern.
WHY
In one word two words: Lazy Instantiation.
There will be many times where you will be creating rather heavy weight object. Objects whose creation not only takes a lot of time but also hogs the resources. You will want to delay the creation of such objects as much as possible. What usually is done is to create a small light weight placeholder which acts as a frontend for the heavyweight object. The client interacts with this placeholder. Once the heavy weight object is really needed then the placeholder internally will create the heavyweight object. The client never knows about this small trickery. All it knows that the heavyweight object was always ready for it to use. This placeholder is called the Proxy. And this pattern is called the Proxy design pattern.
There are other uses for the proxy pattern. Like providing some kind of Authentication. Or hiding the network communication happening behind the scene from the client. Or even adding a little pre processing before handing off the request to the big fat object. But lazy instantiation is probably the most common use of it.
HOW
The idea is very simple. Proxy essentially is a wrapper around the class of interest. What usually is done is to have an interface which the client will know about. The base object will implement the interface. The proxy will also implement it. Client will create an instance of the proxy an use it.
Now I think it is time for some code. In our code we will have a class called BigShow. Then let us have a proxy for this class called BigShowProxy. We will interact with the proxy egging it to have a fight us. And then when we have insulted it enough, we get Chokeslam‘med. Whoo Hoo.
#include<iostream> #include<string> using namespace std; class IWrestler { public: virtual void ComeOnFightMe(void) = 0; virtual void Insult(string expletives) = 0; virtual ~IWrestler(){} }; class BigShow : public IWrestler { public: BigShow() { //Some really massive amount of resources needed //to bring it to life. } void ComeOnFightMe(void) { cout << "\nMassive ignore."; } void Insult(string expletives) { cout << "\nYou just got CHOKESLAMMED.\n\n"; } }; class BigShowProxy : public IWrestler { BigShow* sub; public: BigShowProxy() :sub(NULL){} void ComeOnFightMe(void) { cout << "\nJust run away please !!! (psst This is proxy speaking, not the BigShow)\n"; } void Insult(string expletives) { if (sub == NULL) { sub = new BigShow(); } sub->Insult(expletives); } ~BigShowProxy() { delete sub; } }; int main() { IWrestler* bigShow = new BigShowProxy(); bigShow->ComeOnFightMe(); cout << "\n"; bigShow->Insult("Scared eh BigShow?"); delete bigShow; return 1; }
Let us go through the important lines.
Line 06: This is the interface which has the methods which the client will use.
Line 09: This is basically looking for trouble.
Line 10: Never do this to a wrestler.
Line 14: BigShow, the wrestler class!!
Line 17: Creation of an object of this class understandably takes lots of resources.
Line 23: BigShow ignores mere mortals.
Line 28: BigShow delivers a massive chokeslam. You do not mess with BigShow.
Line 34: The proxy for BigShow.
Line 36: The proxy will create an instance of BigShow. But only when needed.
Line 41: Notice that when asked for a fight, it is Proxy which says scram off. Not the BigShow. BigShow object still not created. If the client gives up at that point, BigShow will not be created. This is a saving of resources. And the intent of proxy pattern. To delay the creation of heavyweight objects as much as possible.
Line 46: But what happens when client starts insulting?
Line 48: If BigShow has not been created
Line 50: Then create BigShow.
Line 52: In a sneaky way, proxy passes the insults to BigShow. Who then delivers justice.
Line 63: Create an instance of proxy.
Line 64: Egging on for a fight.
Line 66: And go on to insult. And this is what happens.
As a bonus I will add a sample C++ implementation of Proxy design pattern to illustrate its use in authentication.
The program below is simple.
#include<iostream> #include<string> using namespace std; class IBank { public: virtual string WithDrawCash(void) = 0; virtual ~IBank(){} }; class ActualBank : IBank { public: string WithDrawCash(void) { return "Here, have a million Zimbabwean dollars.\n\n"; } }; class Bank : public IBank { ActualBank* _bank; string _password; public: Bank() :_bank(NULL), _password("WhoWhatWhere"){} string WithDrawCash(void) { if (_bank == NULL) return "\nDid you authenticate?\n"; return _bank->WithDrawCash(); } void Authenticate(string passwd) { if (_password == passwd) { cout << "\nYou have been authenticated.\n\n"; _bank = new ActualBank(); } else { cout << "\nSorry but wrong.\n"; } } ~Bank() { delete _bank; } }; int main() { Bank* daddysBank = new Bank(); cout << daddysBank->WithDrawCash(); daddysBank->Authenticate("Hello"); daddysBank->Authenticate("WhoWhatWhere"); cout << daddysBank->WithDrawCash(); return 1; }
And the result is: