16. 책임 연쇄 패턴(Chain of Responsibility Pattern)
16.1 개요
여러 형식 개체들로 구성된 프로그램을 작성하다 보면 메시지를 보내는 곳에서 이를 받아서 처리해야 할 개체의 위치를 파악하기 어려운 경우가 있습니다. 만약, 메시지를 받아 처리해야 할 개체들을 관리하는 집합체가 있거나 계층화되어 있다면 책임 연쇄 패턴을 통해 효과적으로 메시지를 전달할 수 있습니다.
책임 연쇄 패턴에서는 메시지 송신자는 이를 받아 처리해야 할 개체가 속한 집합체에 메시지를 전달하면 집합체 내에서 수신해야 할 개체에게 메시지를 전달하여 처리를 하게 하는 것입니다. 집합체에 특정 개체에게 메시지가 전달되면 해당 메시지를 자신이 처리를 할 것인지를 판단하게 됩니다. 만약, 자신이 처리를 해야 한다면 이에 대한 처리를 하겠죠. 그리고 해당 메시지를 처리해야 할 다른 개체가 존재할 수 있다면 이를 다시 전달하게 됩니다. 경우에 따라서는 메시지를 변형하여 전달할 수도 있고 버릴 수도 있을 것입니다.
즉, 책임 연쇄 패턴에서는 메시지 송신부와 메시지 수신부가 분리되어 있을 때 효과적입니다. 송신부에서는 수신부에 전달하면 수신부에서 메시지를 전달받은 개체는 자신과 연관되는 다른 개체들에게 이 메시지를 전달하는 형태로 실제 처리할 개체까지 전달하는 것입니다. 윈도우즈 프로그램에서 메시지를 처리하는 내부 원리도 이와 비슷합니다.
16. 2 시나리오
지난 주에는 EH Camera의 창립 기념 행사에 참석을 하였습니다. 행사 뒤풀이에서 이 매핑 씨와 여행과 사진에 관한 많은 얘기를 했어요. 또한, 집에서 사진 보정 프로그램을 만들어 사용하는 얘기도 하게 되었고 지난 번에 퍼사드 패턴을 적용하여 사진 관리와 보정에 관한 통합 모듈에 대하여 얘기도 했답니다. 그리고 이 매핑 씨는 카메라에 새로운 영상 처리 모듈들이 추가될 때마다 사용자 설정에 맞는 각 모듈에게 영상 처리 명령을 전달하기 위해 비슷한 작업을 수행하는 비용이 많이 든다고 얘기하더군요. 저도 사진 보정 프로그램에 영상 처리 모듈을 추가할 때마다 비슷한 작업이 반복되는 것 같아 이를 수정할 필요성을 느끼고 있었다고 얘기하고 이에 대해 개발 팀과 별도로 미팅을 갖기로 했어요.
어제는 지난 EH Camera 창림 기념 행사에서 이 매핑씨와 했던 얘기가 생각나서 사진 보정 프로그램 설계를 수정했습니다. 일단, UI 파트와 영상 처리 모듈 파트를 분리하는 작업을 하였죠. 그리고 각 모듈들의 추상화 된 모듈을 추가하였습니다. 그리고 이전 설계에서는 없었던 것을 하나 추가했습니다. 영상 처리 모듈은 다른 영상 처리 모듈에게 사용자 명령을 전달할 수 있게 한 것이죠. 추상화 된 모듈을 설계하고 나서 각 모듈은 이를 기반으로 파생하게 만들고 영상 처리 모듈은 다음 등록된 영상 처리 모듈의 위치를 알게 했습니다. 이와 같이 하면 사용자가 사진 보정 명령을 내렸을 때 UI 파트에서는 맨 앞에 있는 영상 처리 모듈에게 보정 명령을 내리고 해당 모듈에서는 자신이 처리할 것인지에 따라 처리할 수 있고 해당 명령을 다음 모듈에게 전달할 수도 있습니다. 이와 같은 동작을 반복하면 새로운 영상 처리 모듈이 추가되더라도 프로그램을 업그레이드하는 데 비용이 줄어들 거라 생각이 되네요.
이제, 이 매핑 씨를 만나 EH Camera 개발 팀과 이에 대하여 얘기하러 갈게요.
AboutChainOfResponsibility.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)
//ChangeHandler.h
#pragma once
#include "common.h"
typedef vector<int> Mode;
typedef vector<int>::const_iterator MIter;
class ChangeHandler
{
ChangeHandler *successor;
const int hid;
public:
ChangeHandler(int hid):hid(hid)
{
successor = 0;
}
virtual string ChangeRequest(Mode mode,string picture)=0;
void SetSuccessor(ChangeHandler *successor)
{
this->successor = successor;
}
ChangeHandler *GetSuccessor()const
{
return successor;
}
protected:
bool IncludeMode(Mode mode)
{
MIter seek= mode.begin();
MIter end= mode.end();
for( ; seek != end; ++seek)
{
if((*seek)==hid)
{
return true;
}
}
return false;
}
};
//GrayChangeHandler.h
#pragma once
#include "ChangeHandler.h"
class GrayChangeHandler :
public ChangeHandler
{
public:
GrayChangeHandler(int hid):ChangeHandler(hid)
{
}
virtual string ChangeRequest(Mode mode,string picture)
{
if(IncludeMode(mode))
{
int index=-1;
while((index = picture.find("칼라",index+1))!=-1)
{
picture.replace(index,strlen("칼라"),"흑백");
}
}
ChangeHandler *successor = GetSuccessor();
if(successor != 0)
{
picture = successor->ChangeRequest(mode,picture);
}
return picture;
}
};
//RedEyeChangeHandler.h
#pragma once
#include "ChangeHandler.h"
class RedEyeChangeHandler :
public ChangeHandler
{
public:
RedEyeChangeHandler(int hid):ChangeHandler(hid)
{
}
virtual string ChangeRequest(Mode mode,string picture)
{
if(IncludeMode(mode))
{
int index=-1;
while((index = picture.find("빨간눈",index+1))!=-1)
{
picture.replace(index,strlen("빨간눈"),"정상눈");
}
}
ChangeHandler *successor = GetSuccessor();
if(successor != 0)
{
picture = successor->ChangeRequest(mode,picture);
}
return picture;
}
};
//SoftChangeHanler.h
#pragma once
#include "ChangeHandler.h"
class SoftChangeHanler :
public ChangeHandler
{
public:
SoftChangeHanler(int hid):ChangeHandler(hid)
{
}
virtual string ChangeRequest(Mode mode,string picture)
{
if(IncludeMode(mode))
{
int index=-1;
while((index = picture.find("날카로운",index+1))!=-1)
{
picture.replace(index,strlen("날카로운"),"부드러운");
}
}
ChangeHandler *successor = GetSuccessor();
if(successor != 0)
{
picture = successor->ChangeRequest(mode,picture);
}
return picture;
}
};
//UIPart.h
#pragma once
#include "GrayChangeHandler.h"
#include "SoftChangeHanler.h"
#include "RedEyeChangeHandler.h"
class UIPart
{
ChangeHandler *head;
ChangeHandler *tail;
public:
UIPart(void);
void AddChangeHandler(ChangeHandler *handler);
string ChangeRequest(Mode mode,string subject);
};
//UIPart.cpp
#include "UIPart.h"
UIPart::UIPart(void)
{
head = tail = 0;
}
void UIPart::AddChangeHandler(ChangeHandler *handler)
{
if(head)
{
tail->SetSuccessor(handler);
tail = handler;
}
else
{
head = tail = handler;
}
}
string UIPart::ChangeRequest(Mode mode,string subject)
{
if(head)
{
return head->ChangeRequest(mode,subject);
}
return subject;
}
//Demo.cpp
#include "UIPart.h"
int main()
{
string picture = "";
Mode mode;
ChangeHandler *handlers[3];
handlers[0] = new GrayChangeHandler(0);
handlers[1] = new SoftChangeHanler(1);
handlers[2] = new RedEyeChangeHandler(2);
UIPart *uipart = new UIPart();
uipart->AddChangeHandler(handlers[0]);
uipart->AddChangeHandler(handlers[1]);
uipart->AddChangeHandler(handlers[2]);
picture = uipart->ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
cout<<picture<<endl;
mode.push_back(0);
picture = uipart->ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
cout<<picture<<endl;
mode.push_back(2);
picture = uipart->ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
cout<<picture<<endl;
mode.push_back(1);
picture = uipart->ChangeRequest(mode,"칼라 빨간눈 날카로운 몸매");
cout<<picture<<endl;
for(int i = 0; i<3; i++)
{
delete handlers[i];
}
delete uipart;
return 0;
}
|
'프로그래밍 기술 > Escort GoF의 디자인 패턴' 카테고리의 다른 글
21. 메멘토 패턴(Memento Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
---|---|
20. 중재자 패턴(Mediator Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
19. 반복자 패턴(Iterator Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
18. 해석자 패턴(Interpreter Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
17. 명령 패턴(Command Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
15. 프락시 패턴(Proxy Pattern) - 스마트 참조자 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
14. 프락시 패턴(Proxy Pattern) - 보호용 프락시 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
13. 프락시 패턴(Proxy Pattern) - 가상 프락시 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
12. 프락시 패턴(Proxy Pattern) - 원격지 프락시 [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
11. 플라이급 패턴(Flyweight Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |