A person having a bank account never interacts with the account physically. If he wants to withdraw money, he can use an ATM card or a cheque.
ATM/cheque act as representatives of the account. They can be called as proxies.
Proxy is an object that represents another object.
Proxy is required to control access to the real object.
Provide a surrogate or placeholder for another object to control access to it.
One reason for controlling access to an object is to defer the full cost of its creation and initialization until it is actually needed.
For example if you load a word document which has lots of embedded images in it, the images are not loaded until their position in the document becomes visible. Instead their position is represented by a rectangle (proxy).
A virtual proxy is a placeholder for "expensive to create" objects. The real object is only created when a client first requests/accesses the object.
A remote proxy provides a local representative for an object that resides in a different address space. This is what the "stub" code in RPC and CORBA provides.
A protective proxy controls access to a sensitive master object. The "surrogate" object checks that the caller has the access permissions required prior to forwarding the request.
A smart proxy interposes additional actions when an object is accessed.
Following is an example of virtual/protective proxy.
#include <iostream>
#include <fstream>
#define NUM_ACCOUNTS 3
#define PASSWORD 123
using namespace std;
class AccountsInterface {
public:
virtual int getBalance(int i) = 0;
};
class HugeListOfAccounts : public AccountsInterface {
private:
char accountFileName[50]; //all accounts have format: account_nnnn.txt
int accountBalances[NUM_ACCOUNTS+1];
void updateBalances() {
for (int i=1; i<=NUM_ACCOUNTS; i++)
{
sprintf(accountFileName, "account_%d.txt", i);
ifstream inFile(accountFileName); // input
if(!inFile) {
cout << "Cannot open input file: " << accountFileName << endl; }
else {
inFile >> accountBalances[i];
inFile.close();
}
}
}//updateBalances
public:
HugeListOfAccounts() {
cout << "ctor: hugeListOfAccounts, updating accountBalances \n";
updateBalances();
}
int getBalance(int i) {return accountBalances[i];}
};
class AccountsProxy : public AccountsInterface {
HugeListOfAccounts *hugeListInstance;
public:
AccountsProxy() {
hugeListInstance = NULL; }//dont build until first access}
int getBalance(int i) {
int ipassword;
cout << "password please: ";
cin >> ipassword;
if (ipassword == PASSWORD) {
if (hugeListInstance==NULL) hugeListInstance = new HugeListOfAccounts;
return hugeListInstance->getBalance(i);
}
else {cout << "Password incorrect \n"; return -999;
}
}
};
int main() {
AccountsInterface *accounts = new AccountsProxy;
int accountNum = 1;
while (accountNum >0 && accountNum <= NUM_ACCOUNTS)
{
cout << "Testing Accounts Proxy \n" << endl;
cout << "enter account number: ";
cin >> accountNum;
cout << accounts->getBalance(accountNum) << endl;
}
return 0;
}
Advantages:
The proxy pattern introduces a level of indirection when accessing the object and can be useful.
Remote proxy can hide the fact that the real object resides in a different address space.
A virtual proxy can perform certain optimizations such as creating object on demand.
Protection and smart proxies allow certain housekeeping tasks when an object is accessed.
Disadvantage:
There may be tight coupling between the proxy and the subject.
Performance hit due to call indirection.
When to use this pattern:
Proxy is applicable whenever you want to prevent clients from accessing the real object because
- The object is in different address space.
- Creating an object is expensive.
- The real object should not be accessed directly