There are four common situations in which the Proxy pattern is applicable.
The Proxy is a "wrapper" that delegates to the real object.
| Before | After | |
|---|---|---|
// Direct coupling, lots of start-up and shut-down
// overhead
class Image {
int m_id;
static int s_next;
public:
Image() { m_id = s_next++;
cout << " $$ ctor: "<< m_id << '\n'; }
~Image() {
cout << " dtor: " << m_id << '\n'; }
void draw() {
cout << " drawing image " << m_id << '\n'; }
};
int Image::s_next = 1;
int main( void ) {
Image images[5];
for (int i; true; ) {
cout << "Exit[0], Image[1-5]: ";
cin >> i;
if (i == 0)
break;
images[i-1].draw();
} }
// $$ ctor: 1
// $$ ctor: 2
// $$ ctor: 3
// $$ ctor: 4
// $$ ctor: 5
// Exit[0], Image[1-5]: 2
// drawing image 2
// Exit[0], Image[1-5]: 4
// drawing image 4
// Exit[0], Image[1-5]: 2
// drawing image 2
// Exit[0], Image[1-5]: 0
// dtor: 5
// dtor: 4
// dtor: 3
// dtor: 2
// dtor: 1
|
// Initialization on first use
// 1. Design an "extra level of indirection" wrapper class
// 2. The wrapper class holds a pointer to the real class
// 3. The pointer is initialized to null
// 4. When a request comes in, the real object is created
// "on first use" (aka lazy intialization)
// 5. The request is always delegated
class RealImage {
int m_id;
public:
RealImage( int i ) { m_id = i;
cout << " $$ ctor: "<< m_id << '\n'; }
~RealImage() {
cout << " dtor: " << m_id << '\n'; }
void draw() {
cout << " drawing image " << m_id << '\n'; }
};
// 1. Design an "extra level of indirection" wrapper class
class Image {
// 2. The wrapper class holds a pointer to the real class
RealImage* m_the_real_thing;
int m_id;
static int s_next;
public:
Image() {
m_id = s_next++;
// 3. Initialized to null
m_the_real_thing = 0;
}
~Image() { delete m_the_real_thing; }
void draw() {
// 4. When a request comes in, the real object is
// created "on first use"
if ( ! m_the_real_thing)
m_the_real_thing = new RealImage( m_id );
// 5. The request is always delegated
m_the_real_thing->draw();
} };
int Image::s_next = 1;
int main( void ) {
Image images[5];
for (int i; true; ) {
cout << "Exit[0], Image[1-5]: ";
cin >> i;
if (i == 0)
break;
images[i-1].draw();
} }
// Exit[0], Image[1-5]: 2
// $$ ctor: 2
// drawing image 2
// Exit[0], Image[1-5]: 4
// $$ ctor: 4
// drawing image 4
// Exit[0], Image[1-5]: 2
// drawing image 2
// Exit[0], Image[1-5]: 0
// dtor: 4
// dtor: 2
|
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. [GoF, p220]