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