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]