Proxy clss

반응형


Proxy : 대리자.

목적 : 직관적인 연결, 생성과 파괴에 대한 부하 방지

Ex
#include <iostream>
#include <string>
using namespace std;

class Image
{
 int id;
 static int next;

public:
 Image()
 {
  id = next++; 
  cout<<" $$ ctor: "<<id<<endl;
 }
 ~Image()
 {
  cout<<" dtor: "<<id<<endl;
 }
 void draw()
 {
  cout<<" drawing image "<<id<<endl;
 }
};
int Image::next = 1;


int _tmain(int argc, _TCHAR* argv[])
{
 // 잦은 생성 - 5번의 생성자 호출
 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;
 }
 getchar();
 return 0;
}

결과
//    $$ 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


목적 : Proxy esing 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 initialization) 
5.  The request is always delegated


Ex
#include <iostream>
#include <string>
using namespace std;

class RealImage
{
 int id;
public:
 RealImage(int i)
 {
  id = i;
  cout<<" && ctor: "<<id<<endl;
 }
 ~RealImage()
 {
  cout<<" dtor: "<<id<<endl;
 }
 void draw()
 {
  cout<<" drawing image "<<id<<endl; 
 }
};

// 1. "간접참조의 추가적인 부분"의 랩핑 클래스  
class Image
{
 // 2. 실제 객체에 대한 포인터
 RealImage* theRealThing;
 int   id;
 static int next; 
public:
 Image()
 {
  id = next++;
  theRealThing = NULL;  // 3. null로 초기화
 }
 ~Image()
 {
  delete theRealThing;
 }

 void draw()
 {
  // 4. 요구가 들어올때 실제 객체가 만들어 진다.
  if(!theRealThing)
   theRealThing = new RealImage(id);

  // 5. 요구는 항상 위임되어진다.
  theRealThing->draw();
 }
};
int Image::next = 1; 


int _tmain(int argc, _TCHAR* argv[])
{
 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;
 }
 getchar();
 return 0;
}

결과
// 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

결론
아까와는 결과가 확연이 다르다.
중간에 wrapper클래스를 둠으로써 생성자의 호출을 최대한 뒤로 미루게 되었다.
그럼으로써 굳이 생성하지 않아도 될 자원을 생성하는 부하를 막을 수 있었다.

목적 : "->"와 "." 연산자가 다른 결과를 가진다.

Ex

class Subject
{
public:
 virtual void execute() = 0;
};

class RealSubject : public Subject
{
 string str;
public:
 RealSubject(string s)
 {
  str = s;
 }

 virtual void execute() // virtual을 붙이든 붙이지 않든 가상함수 테이블은 만들어 지는걸까?
 {
  cout<<str<<endl;
 }
};

class ProxySubject : public Subject
{
 string first, second, third;
 RealSubject* ptr; // real의 object
public:
 ProxySubject(string s)
 {
  int num = (int)s.find_first_of(' '); // 처음으로 공백이 나오는 위치
  first = s.substr(0, num);    // 0부터 num 위치까지 카피
  s = s.substr(num+1);     // 해당위치부터 끝까지 리턴

  num = (int)s.find_first_of(' ');   
  second = s.substr(0, num);
  s = s.substr(num+1);
  
  num = (int)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(); 
 }
};


int _tmain(int argc, _TCHAR* argv[])
{
 // 2.
 ProxySubject obj(string("the quick brown fox jumped over the dog"));
 obj->execute();
 obj.execute();
 getchar();
 return 0;
}

결과
// the quick fox jumped over the dog
// the brown fox jumped over the dog

결론
이 예에서는 이전 예제처럼 기다렸다가 real을 생성하는것 외에 다른것을 말하려고 하는것 같다.
즉, 프록시 클래스를 활용하면 클래스 객체에 대한 연산자 오버로딩을 활용할 수 있다는 것인듯.
이 예에서는 "->" 와 "."에 다른 처리를 하고자 프로시클래스에서 "->"연산자를 오버로딩하였다.

목적 : real object에 접근하기 위한 protection proxy 컨트롤들

EX
class Person                      // 사람들의 목록
{
 string nameString;
 static string list[];
 static int next;
public:
 Person()
 {
  nameString = list[next++];
 }
 string name()
 {
  return nameString;
 }
};
string Person::list[] = {"AA", "BB", "CC", "DD"};
int Person::next = 0;
 
class PettyCashProtected    // pc에서 접근을 제어해서 관리해야 할 부분. (잔액)
{
 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             // pc에서 공개로 사용하는 부분
{
 PettyCashProtected realThing;       // pc의 비공개에 접근하는 object
public:
 bool withdraw(Person& p, int amount)
 {
  if(p.name() == "AA" || p.name() == "CC" || p.name() == "DD" ) 
   return realThing.withdraw(amount); 
  else
   return false;
 }

 int getBalance()
 {
  return realThing.getBalance();
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
 
 // 3.
 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()<<endl;
  else
   cout<<amount<<" dollars for "<<workers[i].name()<<endl;
 }
 cout<<"Remaining balance is "<<pc.getBalance()<<endl;

 getchar();
 return 0;
}

결과
// 100 dollars for Tom
// No money for Dick
// 300 dollars for Harry
// No money for Bubba
// Remaining balance is 100

결론
이 예에서는 pc의 protected한 클래스를 만들어 두고 이곳에 접근하기 위한 용도로 pc클래스(proxy)를 만든듯 하다.
즉 proxy는 대리자로서 real object에 접근이 가능하다.


목적 : Persistent Object Pointer 인 척 하기

EX
template <typename T> class POP // Persistent Object Pointer
{
 string oid;
 T*    ptr;
public:
 POP(string id)
 {
  oid = id;
  ptr = NULL;
 }
 ~POP()
 {
  delete ptr;
 }

 T* operator->()
 {
  if(!ptr)
   ptr = new T(oid); //simulate the persistence mechanism
  return ptr;
 }
};

class Men
{
 string name;
 int age;
public:
 Men(string n)
 {
  name = n;
 }
 string getName()
 {
  return name;
 }
 int getAge()
 {
  return 32;
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
// 4.
 POP<Men> ph("사람a");
 cout<<"policy holder is "<<ph->getName()<<", age is "<<ph->getAge()<<endl;
 getchar();
 return 0;
}

결과
// policy holder is Tom, age is 32


결론
이 예는 확실히 무었을 말하려하는지 잘 와닿지는 않는데...
대략적으로 템플릿클래스를 proxy로 쓰겠다는 말인듯 하다.
나머지 -> 연산자 오버로딩이야 위에서 했으니까.머...

'Study > C++' 카테고리의 다른 글

bitarray 제작, 활용  (0) 2009.07.20
bitarray  (0) 2009.07.18
디자인 패턴  (0) 2009.07.16
explicit 키워드에 대해서.  (0) 2009.07.14
string -> char* -> WCHAR* 타입 변환  (0) 2009.07.14
TAGS.

Comments