Proxy
Intention
- Provide a surrogate or placeholder for another object to control access to it.
- Use an extra level of indirection to support distributed, controlled, or intelligent access.
- Add a wrapper and delegation to protect the real component from undue complexity.
Application
- 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.
Counting the number of references to the real object so that it can be freed automatically when there are no more references (aka smart pointer),
Loading a persistent object into memory when it’s first referenced,
Checking that the real object is locked before it is accessed to ensure that no other object can change it.
Checklist
- Identify the leverage or “aspect” that is best implemented as a wrapper or surrogate.
- Define an interface that will make the proxy and the original component interchangeable.
- Consider defining a Factory that can encapsulate the decision of whether a proxy or original object is desirable.
- The wrapper class holds a pointer to the real class and implements the interface.
- The pointer may be initialized at construction, or on first use.
- Each wrapper method contributes its leverage, and delegates to the wrappee object.
Thumb Rules
- Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.
- Decorator and Proxy have different purposes but similar structures. Both describe how to provide a level of indirection to another object, and the implementations keep a reference to the object to which they forward requests.
Code
#include <iostream>
using namespace std;
class A
{
public:
virtual void execute() = 0;
virtual ~A() {};
};
class RealA : public A
{
public:
RealA() {cout << "RealA ctor \n";}
void execute()
{
cout << "RealA executed \n";
}
~RealA() {cout << "RealA dtor \n";}
};
#define VALID_ACCESS_ID 123
#define LIMITED_ACCESS_ID 1234
// 1. Design an "extra level of indirection" wrapper class
class ProxyA : public A
{
int m_accessId;
RealA *realA;
public:
ProxyA(int accessId)
{
m_accessId = accessId;
// 3. Initialized to null
realA = NULL;
cout << "ProxyA ctor \n";
}
void execute()
{
if(VALID_ACCESS_ID != m_accessId)
{
cout << "Access Denied \n";
return;
}
// 2. The wrapper class holds a pointer to the real class
if(!realA)
realA = new RealA();
realA->execute();
}
~ProxyA()
{
if(realA)
delete realA;
cout << "ProxyA dtor \n";
}
};
int main()
{
A *a1 = new ProxyA(VALID_ACCESS_ID);
a1->execute();
delete a1;
A *a2 = new ProxyA(LIMITED_ACCESS_ID);
a2->execute();
delete a2;
system("PAUSE");
return 1;
}
ProxyA ctor
RealA ctor
RealA executed
RealA dtor
ProxyA dtor
ProxyA ctor
Access Denied
ProxyA dtor