프로그래밍 기술/Escort GoF의 디자인 패턴

12. 프락시 패턴(Proxy Pattern) - 원격지 프락시 [Escort GoF의 디자인 패턴]

언제나휴일 2016. 4. 4. 14:12
반응형

12. 프락시 패턴(Proxy Pattern) - 원격지 프락시

 

12.1 개요

 

 프락시 패턴은 사용자가 사용하는 개체를 통해 실제 개체를 제어하게 하는 패턴입니다.

 

 프락시 패턴을 사용하는 경우에는 제어하기 위한 개체가 사용자와 위치가 다른 경우에 사용자가 원격지에 있는 개체에 접근하기 쉽게 할 경우가 있습니다(원격지 프락시). 그리고 실제 개체의 특정 행위를 호출할 때 해당 작업이 완료되기를 기다리는 비용이 크다면 작업 요청을 대행하는 프락시 개체를 두어 사용자가 작업이 완료되기를 기다리지 않게 할 수 있습니다(가상 프락시). 이 외에도 권한에 따라 사용할 수 있는 수준이 다른 실 개체를 보호하기 위해 프락시 개체를 제공하는 방법(보호용 프락시)과 여러 곳에서 하나의 개체를 사용해야 한다면 참조 카운터를 두고 프락시 개체를 제공(스마트 포인터)할 수 있습니다.

 

 원격지 프락시는 서버 측에 있는 실제 개체와 같은 인터페이스를 갖는 원격지 개체를 제공하게 됩니다. 그리고 서버 측에는 원격지 개체와 통신을 담당하여 서버 측에 있는 개체를 제어하게 하는 원리입니다. 이 때 원격지 개체를 원격지 프락시 개체라 얘기합니다. 그리고 서버 측에서 원격지 프락시 개체와 통신하여 실제 개체를 사용하는 개체를 스텁(Stbu) 개체라 부릅니다.

 

 프락시 패턴을 사용하면 Client 측에서 원격 프락시 개체를 실제 개체처럼 쉽게 사용할 수 있게 됩니다.

 

 원격지 프락시에 대한 예제에서는 간단한 소켓 통신을 사용할 것입니다.

 

12. 2 시나리오

 

 이번 주에는 여수에서 엑스포가 있어 바람 쐬러 갑니다. 아내와 아들은 여수 엑스포의 다양한 행사 중에서 야간에 진행되는 행사들에 관심이 많습니다. 예전부터 생각하고 있었는데 이번 기회에 리모트 컨트롤러를 사기로 했습니다


원격지 프락시 패턴


AboutClient.zip


AboutRemoteProxy.zip

서버 코드

//common.h

#pragma once

 

#pragma warning (disable:4996)

#include <iostream>

 

using std::cout;

using std::endl;

#include <vector>

using std::vector;

#include <string>

using std::string;

 

#include <iomanip>

using std::ios;

#include <algorithm>

 

#pragma warning(disable:4482)

 

//ITake.h

#pragma once

#include "common.h"

 

#define TAKE         0x01

#define CHANGE    0x02

#define GET          0x03

 

class ITake

{

public:

             virtual string TakeAPicture()=0;                        

             virtual void ChangeMode(bool mode)=0;

             virtual bool GetMode()=0;

};

 

//Camera.h

#pragma once

#include "ITake.h"

class Camera:public ITake

{

             bool mode;

public:

             Camera(void);       

             virtual string TakeAPicture(); 

             virtual void ChangeMode(bool mode);

             virtual bool GetMode();

};

 

//Camera.cpp

#include "Camera.h"

 

Camera::Camera(void)

{

             mode = false;

}

 

 

string Camera::TakeAPicture()

{

             cout<<"사진을 찍습니다."<<endl;

             if(mode)

             {

                           return "수동모드로 찍힌 사진";

             }

             return "자동모드로 찍힌 사진";

}

void Camera::ChangeMode(bool mode)

{

            

             this->mode = mode;

             if(mode)

             {

                           cout<<"수동 모드로 변환되었습니다."<<endl;

             }

             else

             {

                           cout<<"자동 모드로 변환되었습니다."<<endl;

             }

}

bool Camera::GetMode()

{           

             if(mode)

             {

                           cout<<"수동 모드입니다."<<endl;

             }

             else

             {

                           cout<<"자동 모드입니다."<<endl;

             }

             return mode;

}

 

//Stub.h

#pragma once

#include "ITake.h"

#include <winsock2.h>

#pragma comment(lib,"ws2_32")

class Stub

{

             ITake *itake;          

             SOCKET sock;

public:   

             Stub(SOCKET dosock,ITake *itake);

             void Do();

             ~Stub(void);

private:

             void TakeProc();

             void ChangeProc();

             void GetProc();

};

 

//Stub.cpp

#include "Stub.h"

 

 

Stub::Stub(SOCKET dosock,ITake *itake)

{

             sock = dosock;

             this->itake = itake;

}

void Stub::Do()

{

             int msgid =0;

            

             recv(sock,(char *)&msgid,sizeof(msgid),0);

             switch(msgid)

             {

             case TAKE:            TakeProc(); break;

             case CHANGE: ChangeProc(); break;

             case GET: GetProc(); break;

             }

}

void Stub::TakeProc()

{

             string picture = itake->TakeAPicture();

             char buf[256];

             strcpy(buf,picture.c_str());

             send(sock,buf,256,0);

}

void Stub::ChangeProc()

{

             bool mode;

             recv(sock,(char *)&mode,sizeof(mode),0);

             itake->ChangeMode(mode);

}

void Stub::GetProc()

{

             bool mode;

             mode = itake->GetMode();

             send(sock,(char *)&mode,sizeof(mode),0);

}

Stub::~Stub(void)

{

             closesocket(sock);

}

 

//ListenServer.h

#pragma once

 

 

#include <winsock2.h>

#pragma comment(lib,"ws2_32")

#include <windows.h>

#include "Stub.h"

class ListenServer

{

public:

             ListenServer(ITake *itake);

             ~ListenServer(void);

private:

             static DWORD WINAPI DoIt(LPVOID pin);

};

 

//ListenServer.cpp

#include "ListenServer.h"

 

ListenServer::ListenServer(ITake *itake)

{

             SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

             SOCKADDR_IN servaddr = {0,};

             servaddr.sin_family = PF_INET;

             servaddr.sin_addr.s_addr =  inet_addr("자신의 IP 주소");

             servaddr.sin_port = htons(10200);

             bind(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));

             listen(sock,5);

 

             SOCKADDR_IN clientaddr;

             int len = sizeof(clientaddr);

             SOCKET dosock;

             DWORD ThreadID;

             Stub *stub =0;

             while(1)

             {

                           dosock = accept(sock,(SOCKADDR *)&clientaddr,&len);                 

                           stub = new Stub(dosock,itake);

                           CloseHandle(CreateThread(0,0,DoIt,stub,0,&ThreadID));

             }

}

 

DWORD WINAPI ListenServer::DoIt(LPVOID pin)

{

             Stub *stub = (Stub *)pin;

             stub->Do();

             delete stub;

             return 0;

}

ListenServer::~ListenServer(void)

{

}

 

//Demo.cpp

#include "ListenServer.h"

#include "Camera.h"

int main()

{

             WSADATA wsadata;

             WSAStartup(MAKEWORD(2,2),&wsadata);

 

             Camera *camera = new Camera();

             ListenServer *listenserver = new ListenServer(camera);       

             WSACleanup();

             return 0;

}

 

 

 

클라이언트 코드

//common.h

#pragma once

 

#pragma warning (disable:4996)

#include <iostream>

 

using std::cout;

using std::endl;

#include <vector>

using std::vector;

#include <string>

using std::string;

 

#include <iomanip>

using std::ios;

#include <algorithm>

 

#pragma warning(disable:4482)

 

//ITake.h

#pragma once

#include "common.h"

 

#define TAKE                      0x01

#define CHANGE    0x02

#define GET                                     0x03

 

class ITake

{

public:

             virtual string TakeAPicture()=0;                        

             virtual void ChangeMode(bool mode)=0;

             virtual bool GetMode()=0;

};

 

//RemoteController.h

#pragma once

#include "ITake.h"

 

#include <winsock2.h>

#pragma comment(lib,"ws2_32")

#include <windows.h>

 

class RemoteController:public ITake

{

public:   

             virtual string TakeAPicture(); 

             virtual void ChangeMode(bool mode);

             virtual bool GetMode();

private:

             SOCKET Connect(int msgid);

};

 

//RemoteController.cpp

#include "RemoteController.h"

 

 

string RemoteController::TakeAPicture()

{

             SOCKET sock = Connect(TAKE);          

             char buf[256];

             recv(sock,buf,256,0);

             closesocket(sock);

             return buf;

}

void RemoteController::ChangeMode(bool mode)

{

             SOCKET sock = Connect(CHANGE);    

             send(sock,(char *)&mode,sizeof(mode),0);

             closesocket(sock);

}

bool RemoteController::GetMode()

{

             SOCKET sock = Connect(GET);           

             bool mode;

             recv(sock,(char *)&mode,sizeof(mode),0);

             closesocket(sock);

             return mode;

}

SOCKET RemoteController::Connect(int msgid)

{           

             SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

             SOCKADDR_IN servaddr = {0,};

             servaddr.sin_family = PF_INET;

             servaddr.sin_addr.s_addr = inet_addr("서버의 IP 주소");

             servaddr.sin_port = htons(10200);

             connect(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));

             send(sock,(char *)&msgid,sizeof(msgid),0);

             return sock;

}

 

//Demo.cpp

#include "RemoteController.h"

int main()

{

             WSADATA wsadata;

             WSAStartup(MAKEWORD(2,2),&wsadata);

             RemoteController *remocon = new RemoteController();

             string s = remocon->TakeAPicture();

             cout<<s<<endl;

             remocon->ChangeMode(true);

             s = remocon->TakeAPicture();

             cout<<s<<endl;

             remocon->ChangeMode(false);

             s = remocon->TakeAPicture();

             cout<<s<<endl;

             bool mode = remocon->GetMode();

             if(mode)

             {

                           cout<<"수동 모드로 변환되었습니다."<<endl;

             }

             else

             {

                           cout<<"자동 모드로 변환되었습니다."<<endl;

             }

             delete remocon;

             WSACleanup();

             return 0;

}

 

IT 전문가로 가는 길 Escort GoF의 디자인 패턴
국내도서
저자 : 장문석
출판 : 언제나휴일 2013.04.01
상세보기


 

반응형