One of my primary C++ goals is to study all of the (Gang of Four) patterns,
From what I understand, there are our common scenarios which would suggest use of a 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.
To make sure I understand this pattern, I wanted to think of a scenario which would require as many of the 4 types of proxies as possible (I was able to come up with 2). Any feedback you can give me would be highly appreciated. Thanks in advance!
P.S. It seems a proxy is needed when the original class had some design shortcomings?
A class (HugeListOfAccounts) is available which provides access to 3 million account balances. The class itself is off-limits, cannot be altered and is (due to file I/O) "expensive to create". We want to have access to those account balances, but only if necessary (virtual proxy) and only to authorized individuals (protective proxy). So we create a virtual/protective proxy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
#include <iostream>
#include <fstream>
#define NUM_ACCOUNTS 3 // 3 million!
#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;
}
|