프록시( Proxy )

Posted 2012. 10. 23. 17:16

본래 객체의 대리 객체 패턴.

즉, 참조 카운팅 포인터 객체이다.

복잡한 객체를 여러개 복사해야 하는 상황이 있다면 어떻게 보면 flyweight와 비슷 하다.

둘다 원본 복합 객체에 대한 참조를 포함한다.


그림이 8장이 있다 치면. 현재 1개의 그림만 보이면 되고

이후 나올 가능성이 있는 7개는 꼭 미리 로드 할 필요가 없다.

물론 메모리가 넉넉하고 로드 비용이 없다고 가정하면 미리 로드 하는것이 좋겠지만

메모리는 한정되어 있고 로드와 해제에 드는 비용도 있으므로 보이는 부부만 그리는게

더 좋은 방법이다.

하지만 문제는 이미지 객체를 할당해놓고 이미지를 실제 할당하지 않아야 하는데. 이미지 객체를

직접 할당하면 할당시 로드를 하게 되는 것이므로 다른 방법이 필요하다. 이때 필요한 것이

대리 객체인 프록시 객체이다.


위 그림을 보면 이미지 프록시 객체가 있는데 그 객체를 이용한다는 뜻이다.

위 그림에는 나와있지 않지만 프록시 객체를 생성시 실제 용량을 차지하는 이미지를 로드하는 코드가

생성자에 있지 않아서 결과적으로 로드가 이루어지지 않은 가상의 이미지 객체가 된다.

이런 식으로 문서의 이미지를 객체화 시켜놓고 실제 모니터 출력 부분에 속할때 Draw명령이 떨어지고

Draw명령 속에서 이미지를 생성하고 그 이미지의 Draw명령을 수행한다.

이것은 전문 용어로 Copy-On-Write라는 기법인데 간단히 말해서 "쓸때쓰자" 이다.

사실 사본의 복사 시기에 관련된 용어이지만 이 상황에도 어울리는 용어다.

Draw가 될때만 이미지를 생성해서 그 이미지를 그리는 실제 이미지가 없어도 문서는 가상 이미지 객체

(프록시 객체)를 생성했으므로 이미지가 있는것으로 취급하며 이미지가 실제로 필요할때 생성하는 유

용한 기법이다.

그림대로 코드를 작성하면

// 문서 생성

TextDocument* text = new TextDocument;

text->Insert( new 이미지Proxy("그림1"));

이렇게 문서에 프록시 형태로 생성하여 삽입해놓으면 초기 할당 비용도 아끼고 메모리도 아낀것이 됨


프록시 객체는 이외에도 여러 다른 역할을 수행 할 수 있습니다.

1. 원격지 프록시 : 현재 공간과는 다른 공간에 존재하는 객체를 대리하는 프록시로써, 현재 공간에 존재하게 된다. 즉, 현재 공간에서 프록시 객체에게 명령을 내리면 프록시 객체는 원격지의 실제 객체에게 명령을 전달해주는 역할을 하게 된다.


2. 가상 프록시 : 방금 위에서 살펴 본 문서 안의 이미지 프록시 객체가 가상 프록시 이다. 간단히 말해 요청이 있을때에만 고비용 객체를 생성 한다.


3. 보호용 프록시 : 방금 위에서 살펴 본 문서 안의 이미지 프록시 객체가 가상 프록시 이다. 간단히 말해 요청이 있을때에만 고비용 객체를 생성한다.


4. 스마트참조자 : 프록시는 어떤 면에서는 포인터의 역할과도 비슷하다. 어떤 객체에 대한 참조자를 단순히 포인터로 지정하지 않고 부가적인 기능이 있는 똑똑한 참조자의 역할로 수행하게 할 수 있다.참조 횟수를 저장하여 객체의 할당, 해제를 자동으로 한다든지, 처음 참조 되는 시점에 메모리에 할당하게 한다든지, 실제 객체에 접근하기 전에 병행 제어를 위해 객체에 대해 잠금을 걸 수 있다.


class RealImage

{

private:

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";

}

};


class Image

{

private:

RealImage *m_the_real_thing;

int m_id;

static int s_next;

public:

Image()

{

m_id = s_next++;

m_the_real_thing = 0;

}

~Image()

{

delete m_the_real_thing;

}

void draw()

{

if( !m_the_real_thing )

m_the_real_thing = new RealImage( m_id );

m_the_real_thing->draw();

}

};

int Image::s_next = 1;


void main()

{    

Image images[5];

for( int i ; true ; )

{

cout << "Exit[0], Image[1-5] : ";

cint >> 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