18. 해석자 패턴(Interpreter Pattern)
18.1 개요
해석자 패턴은 사용자가 표현하기 쉬운 표현을 사용하게 하고 이를 해석하는 개체를 통해 약속된 알고리즘을 수행하는 패턴입니다. SQL 쿼리문이나 Command 창에서 프로그램 실행 시 필요한 인자를 전달하는 경우 등에서 많이 사용될 수 있는 패턴입니다.
해석자 패턴에서는 사용자가 원하는 다양한 명령을 쉽게 표현할 수 있게 구문 약속을 해야 합니다. 그리고 해석자에서는 이와 같이 약속된 구문을 입력 인자로 전달되었을 때 해석할 수 있어야 합니다. 가령 "2 Add 3" 과 같은 표현은 피 연산자:2, 연산자:+, 피 연산자:3 으로 해석될 수 있다는 것입니다.
해석자 패턴을 사용하면 사용자가 다양한 명령을 쉬운 표현 방법으로 전달할 수 있습니다. 하지만, 너무 많은 명령어 조합을 해석자 패턴으로 적용한다면 정규화 과정에 들어가는 비용이 기하급수적으로 커질 수 있습니다. 비교적 사용자가 표현식의 문법이 단순할 수 있다면 효과적이겠지만, 그렇지 않다면 다른 방법을 사용하는 것이 나을 수 있습니다.
18. 2 시나리오
EH Camera 회사의 객원 감수자로 활동을 하면서 개인적으로 만들었던 사진 관리 응용들의 일부 기능들이 요긴하게 사용하게 되었습니다. 하지만, 개인적으로 만들었던 응용과는 달리 좀 더 사용자가 편리하고 효과적으로 사진을 관리하고 보정할 수 있게 만들어야 했습니다. 이러한 이유로 많은 엔지니어가 사용자와 상호 작용하는 부분에 많은 비용이 들게 되더군요.
좀 더 사용자가 편리하고 효과적으로 사진을 관리하고 보정할 수 있는 방법을 생각하다가 각 개인에 따라 사진 보정을 할 때 사용하는 기능은 개인에 따라 매크로를 제공하는 것이 나을 수 있다는 생각을 하게 되었습니다. 그리고 개인이 쉽게 매크로를 만들 수 있는 표현을 생각하게 되었고 이러한 매크로를 분석하여 포함된 기능들을 수행할 수 있게 설계해 보았습니다.
설계에서는 사진을 보정하는 개체를 서로 체인 형태로 연결하고 보정 명령 구문을 해석하여 자신이 수행해야 할 부분에 대하여 해석할 수 있게 하였습니다. 이제는 사용자는 자신이 보정하고자 하는 종류를 매크로에 보관하는 초기 작업과 원하는 보정 구문을 추가하면 매크로 내부에 있는 각 보정 개체가 자신이 수행해야 할 구문을 분석합니다. 이 후 사용자는 보정할 사진을 넣으면 매크로에 보관된 각 보정 개체들이 알아서 보정 작업을 합니다. 이제 간략한 예광탄을 만들어 본 후에 이에 대해 다시 수정을 하거나 보완 작업을 해야겠어요.
//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)
//Picture.h
#pragma once
#include "Common.h"
class Picture
{
string name;
int tone;
int brightness;
int saturation;
public:
Picture(string name,int tone,int brightness,int saturation);
void ChangeTone(int tone);
void ChangeBrightness(int brightness);
void ChangeSaturation(int saturation);
void View()const;
};
//Picture.cpp
#include "Picture.h"
Picture::Picture(string name,int tone,int brightness,int saturation)
{
this->name = name;
this->tone = tone;
this->brightness = brightness;
this->saturation = saturation;
}
void Picture::ChangeTone(int tone)
{
this->tone += tone;
}
void Picture::ChangeBrightness(int brightness)
{
this->brightness += brightness;
}
void Picture::ChangeSaturation(int saturation)
{
this->saturation += saturation;
}
void Picture::View()const
{
cout<<"사진 파일 명:"<<name<<endl;
cout<<" 색조:"<<tone<<" 명도:"<<brightness<<" 채도:"<<saturation<<endl;
}
//Expression.h
#pragma once
#include "Picture.h"
class Expression
{
Expression *next;
public:
Expression()
{
next = 0;
}
virtual string Interpret(string context)=0;
virtual void DoItWithPicture(Picture *picture)
{
if(next)
{
next->DoItWithPicture(picture);
}
}
void SetNext(Expression *next)
{
this->next = next;
}
protected:
string NextInterpret(string context)
{
if(next)
{
return next->Interpret(context);
}
return context;
}
};
//BrighExpression.h
#pragma once
#include "Expression.h"
class BrighExpression :
public Expression
{
int value;
public:
virtual string Interpret(string context)
{
value = 0;
int index = -1;
string be ="";
string af = "";
while( (index = context.find_first_of("B"))!=-1)
{
value += atoi(context.substr(index+strlen("B")).c_str());
if(index>0)
{
be = context.substr(0,index);
}
else
{
be = "";
}
index = context.find(";",index);
af = context.substr(index+1);
context = be+af;
}
return NextInterpret(context);
}
virtual void DoItWithPicture(Picture *picture)
{
picture->ChangeBrightness(value);
Expression::DoItWithPicture(picture);
}
};
//SatuExpression.h
#pragma once
#include "Expression.h"
class SatuExpression:
public Expression
{
int value;
public:
virtual string Interpret(string context)
{
value = 0;
int index = -1;
string be ="";
string af = "";
while( (index = context.find_first_of("S"))!=-1)
{
value += atoi(context.substr(index+strlen("S")).c_str());
if(index>0)
{
be = context.substr(0,index);
}
else
{
be = "";
}
index = context.find(";",index);
af = context.substr(index+1);
context = be+af;
}
return NextInterpret(context);
}
virtual void DoItWithPicture(Picture *picture)
{
picture->ChangeSaturation(value);
Expression::DoItWithPicture(picture);
}
};
//ToneExpression.h
#pragma once
#include "Expression.h"
class ToneExpression:
public Expression
{
int value;
public:
virtual string Interpret(string context)
{
value = 0;
int index = -1;
string be ="";
string af = "";
while( (index = context.find_first_of("T"))!=-1)
{
value += atoi(context.substr(index+strlen("T")).c_str());
if(index>0)
{
be = context.substr(0,index);
}
else
{
be = "";
}
index = context.find(";",index);
af = context.substr(index+1);
context = be+af;
}
return NextInterpret(context);
}
virtual void DoItWithPicture(Picture *picture)
{
picture->ChangeTone(value);
Expression::DoItWithPicture(picture);
}
};
//Macro.h
#pragma once
#include "ToneExpression.h"
#include "SatuExpression.h"
#include "BrightExpression.h"
class Macro
{
Expression *head;
Expression *tail;
string context;
public:
Macro(void);
void AddExpression(Expression *expression);
void ChangePicture(Picture *picture);
void AddContext(string context);
};
//Macro.cpp
#include "Macro.h"
Macro::Macro(void)
{
head = tail = 0;
}
void Macro::AddExpression(Expression *expression)
{
if(head)
{
tail->SetNext(expression);
tail = expression;
}
else
{
head = tail = expression;
}
}
void Macro::ChangePicture(Picture *picture)
{
head->DoItWithPicture(picture);
}
void Macro::AddContext(string context)
{
head->Interpret(context);
}
//demo.cpp
#include "Macro.h"
int main()
{
Expression *ex1 = new ToneExpression();
Expression *ex2 = new BrighExpression();
Expression *ex3 = new SatuExpression();
Macro *macro = new Macro();
macro->AddExpression(ex1);
macro->AddExpression(ex2);
macro->AddExpression(ex3);
macro->AddContext("B 20;");
macro->AddContext("B 20;T-12;S 10;B10;");
Picture *picture = new Picture("현충사의 봄",100,100,100);
macro->ChangePicture(picture);
picture->View();
delete picture;
delete macro;
delete ex1;delete ex2;delete ex3;
return 0;
}
|
'프로그래밍 기술 > Escort GoF의 디자인 패턴' 카테고리의 다른 글
23. 상태 패턴(State Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
---|---|
22. 감시자 패턴(Observer Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
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 |
17. 명령 패턴(Command Pattern) [Escort GoF의 디자인 패턴] (0) | 2016.04.04 |
16. 책임 연쇄 패턴(Chain of Responsibility 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 |