// Purpose. Direct coupling, lots of start-up and shut-down overhead #include #include using namespace std; class Image { int id; static int next; public: Image() { id = next++; cout << " $$ ctor: "<< id << '\n'; } ~Image() { cout << " dtor: " << id << '\n'; } void draw() { cout << " drawing image " << id << '\n'; } }; int Image::next = 1; void main( void ) { Image images[5]; int i; cout << "Exit[0], Image[1-5]: "; cin >> i; while (i) { images[i-1].draw(); cout << "Exit[0], Image[1-5]: "; cin >> i; } } // $$ 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 // Purpose. Proxy design pattern // 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 id; public: RealImage( int i ) { id = i; cout << " $$ ctor: "<< id << '\n'; } ~RealImage() { cout << " dtor: " << id << '\n'; } void draw() { cout << " drawing image " << 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* theRealThing; int id; static int next; public: Image() { id = next++; theRealThing = 0; } // 3. Initialized to null ~Image() { delete theRealThing; } void draw() { // 4. When a request comes in, the real object is created "on first use" if ( ! theRealThing) theRealThing = new RealImage( id ); // 5. The request is always delegated theRealThing->draw(); } }; int Image::next = 1; void main( void ) { Image images[5]; int i; cout << "Exit[0], Image[1-5]: "; cin >> i; while (i) { images[i-1].draw(); cout << "Exit[0], Image[1-5]: "; cin >> i; } } // 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]: 4 // drawing image 4 // Exit[0], Image[1-5]: 0 // dtor: 4 // dtor: 2 // Purpose. "->" and "." operators give different results class Subject { public: virtual void execute() = 0; }; class RealSubject : public Subject { string str; public: RealSubject( string s ) { str = s; } /*virtual*/ void execute() { cout << str << '\n'; } }; class ProxySubject : public Subject { string first, second, third; RealSubject* ptr; public: ProxySubject( string s ) { int num = s.find_first_of( ' ' ); first = s.substr( 0, num ); s = s.substr( num+1 ); num = s.find_first_of( ' ' ); second = s.substr( 0, num ); s = s.substr( num+1 ); num = s.find_first_of( ' ' ); third = s.substr( 0, num ); s = s.substr( num+1 ); ptr = new RealSubject( s ); } ~ProxySubject() { delete ptr; } RealSubject* operator->() { cout << first << ' ' << second << ' '; return ptr; } /*virtual*/ void execute() { cout << first << ' ' << third << ' '; ptr->execute(); } }; void main( void ) { ProxySubject obj( string( "the quick brown fox jumped over the dog" ) ); obj->execute(); obj.execute(); } // the quick fox jumped over the dog // the brown fox jumped over the dog // Purpose. "A protection proxy controls access to the original object." class Person { string nameString; static string list[]; static int next; public: Person() { nameString = list[next++]; } string name() { return nameString; } }; string Person::list[] = { "Tom", "Dick", "Harry", "Bubba" }; int Person::next = 0; class PettyCashProtected { int balance; public: PettyCashProtected() { balance = 500; } bool withdraw( int amount ) { if (amount > balance) return false; balance -= amount; return true; } int getBalance() { return balance; } }; class PettyCash { PettyCashProtected realThing; public: bool withdraw( Person& p, int amount ) { if (p.name() == "Tom" || p.name() == "Harry" || p.name() == "Bubba") return realThing.withdraw( amount ); else return false; } int getBalance() { return realThing.getBalance(); } }; void main( void ) { PettyCash pc; Person workers[4]; for (int i=0, amount=100; i < 4; i++, amount += 100) if ( ! pc.withdraw( workers[i], amount )) cout << "No money for " << workers[i].name() << '\n'; else cout << amount << " dollars for " << workers[i].name() << '\n'; cout << "Remaining balance is " << pc.getBalance() << '\n'; } // 100 dollars for Tom // No money for Dick // 300 dollars for Harry // No money for Bubba // Remaining balance is 100 // Purpose. Simulate a Persistent Object Pointer template class POP { // Persistent Object Pointer string oid; TBD* ptr; public: POP( string id ) { oid = id; ptr = 0; } ~POP() { delete ptr; } TBD* operator->() { if ( ! ptr) // simulate the persistence mechanism ptr = new TBD( oid ); return ptr; } }; class Person { string name; int age; public: Person( string n ) { name = n; } string getName() { return name; } int getAge() { return 32; } }; void main( void ) { POP ph( "Tom" ); cout << "policy holder is " << ph->getName() << ", age is " << ph->getAge() << '\n'; } // policy holder is Tom, age is 32