인터프리터 패턴(Interpreter Pattern) 이해하기
인터프리터 패턴은 언어의 문법을 정의하고, 해당 언어의 문장을 해석하고 실행하는 인터프리터를 구현하기 위한 행동 디자인 패턴입니다. 이 패턴은 주로 **특정 도메인에 특화된 언어(Domain-Specific Language, DSL)**를 처리하거나, 복잡한 표현식을 평가하는 데 사용됩니다.
인터프리터 패턴은 언어의 문법 구조를 객체로 표현하여, 문법을 기반으로 입력을 해석하고 실행할 수 있는 구조를 제공합니다. 이번 포스트에서는 인터프리터 패턴의 개념과 구조, 구현 방법, 장단점 및 사용 사례를 구체적인 예제와 함께 살펴보겠습니다.
인터프리터 패턴이란?
인터프리터 패턴은 간단한 언어의 문법을 정의하고 이를 해석하는 클래스를 구현하기 위한 디자인 패턴입니다. 이 패턴은 문법 규칙을 기반으로 입력을 해석하고, 해당 규칙을 구현한 객체들을 통해 문장을 평가하거나 실행할 수 있도록 합니다.
주요 개념은 언어의 문법을 객체로 표현하는 것으로, 각 문법 규칙에 해당하는 클래스를 만들어 트리 형태로 구성한 뒤, 이를 통해 문장을 해석합니다.
인터프리터 패턴의 구조
인터프리터 패턴의 기본 구조는 다음과 같습니다.
- AbstractExpression (추상 표현식):
- 문법 규칙을 정의하는 공통 인터페이스로, 모든 구체적 표현식 클래스가 구현해야 할 메서드를 정의합니다.
- TerminalExpression (종결 표현식):
- 문법의 단말 기호(기본 규칙)에 해당하는 클래스입니다. 주어진 입력을 해석하여 결과를 반환합니다.
- NonTerminalExpression (비종결 표현식):
- 문법의 비단말 기호(복합 규칙)에 해당하는 클래스입니다. 다른 표현식을 포함하여 더 복잡한 규칙을 처리합니다.
- Context (문맥):
- 해석 중에 필요한 정보를 제공하는 클래스입니다. 문장을 해석하기 위해 필요한 데이터를 유지하거나 전달합니다.
- Client (클라이언트):
- 문법 구조를 생성하고 해석기를 실행하는 사용자입니다.
인터프리터 패턴의 구현 방법
예제 코드: 간단한 산술 표현식 해석기
다음은 산술 표현식(예: "3 + 5")을 해석하고 평가하는 인터프리터를 구현한 예제입니다.
// AbstractExpression (추상 표현식)
public abstract class Expression
{
public abstract int Interpret();
}
// TerminalExpression (종결 표현식): 숫자 표현식
public class NumberExpression : Expression
{
private int _number;
public NumberExpression(int number)
{
_number = number;
}
public override int Interpret()
{
return _number;
}
}
// NonTerminalExpression (비종결 표현식): 덧셈 표현식
public class AddExpression : Expression
{
private Expression _leftExpression;
private Expression _rightExpression;
public AddExpression(Expression left, Expression right)
{
_leftExpression = left;
_rightExpression = right;
}
public override int Interpret()
{
return _leftExpression.Interpret() + _rightExpression.Interpret();
}
}
// NonTerminalExpression (비종결 표현식): 뺄셈 표현식
public class SubtractExpression : Expression
{
private Expression _leftExpression;
private Expression _rightExpression;
public SubtractExpression(Expression left, Expression right)
{
_leftExpression = left;
_rightExpression = right;
}
public override int Interpret()
{
return _leftExpression.Interpret() - _rightExpression.Interpret();
}
}
// Client (클라이언트)
class Program
{
static void Main()
{
// 표현식: (5 + 3) - 2
Expression five = new NumberExpression(5);
Expression three = new NumberExpression(3);
Expression two = new NumberExpression(2);
// (5 + 3)
Expression addExpression = new AddExpression(five, three);
// (5 + 3) - 2
Expression subtractExpression = new SubtractExpression(addExpression, two);
Console.WriteLine($"Result: {subtractExpression.Interpret()}");
}
}
실행 결과
Result: 6
설명
- TerminalExpression:
- NumberExpression 클래스는 숫자를 해석하는 종결 표현식입니다. 숫자를 그대로 반환합니다.
- NonTerminalExpression:
- AddExpression과 SubtractExpression 클래스는 덧셈과 뺄셈을 해석하는 비종결 표현식입니다. 각각 좌측과 우측 표현식을 해석한 결과를 더하거나 뺍니다.
- Client:
- 클라이언트 코드에서 표현식을 트리 형태로 구성한 뒤, 최상위 표현식의 Interpret() 메서드를 호출하여 전체 표현식을 평가합니다.
인터프리터 패턴의 장단점
장점
- 언어 구조화:
- 간단한 언어의 문법을 명확하게 구조화하고 객체로 표현할 수 있습니다.
- 확장성:
- 새로운 문법 규칙이 추가되더라도, 새로운 표현식 클래스를 추가하면 기존 코드를 수정하지 않고 확장할 수 있습니다.
- 유연성:
- 표현식을 트리 형태로 구성하여 복잡한 문법 구조를 처리할 수 있습니다.
단점
- 복잡성 증가:
- 문법 규칙이 많아질수록 표현식 클래스가 많아져 코드가 복잡해질 수 있습니다.
- 성능 문제:
- 트리를 반복적으로 탐색하면서 표현식을 해석하므로, 성능이 중요한 상황에서는 부적합할 수 있습니다.
- 현실적인 제한:
- 복잡한 언어(예: 프로그래밍 언어 전체)를 처리하기에는 인터프리터 패턴이 비효율적일 수 있습니다.
언제 인터프리터 패턴을 사용해야 할까?
인터프리터 패턴은 다음과 같은 상황에서 유용합니다.
- 도메인 특화 언어(DSL)를 처리해야 할 때:
- 간단한 규칙이나 표현식을 가진 언어를 해석하고 실행해야 할 때.
- 문법 구조가 자주 변경되거나 확장될 때:
- 문법이 자주 변경되거나 새로운 규칙이 추가되는 환경에서 유연하게 대처할 수 있습니다.
- 단순한 문법 구조를 처리할 때:
- 복잡한 문법보다는 간단한 규칙을 기반으로 작동하는 언어를 처리하기에 적합합니다.
인터프리터 패턴과 관련 패턴 비교
인터프리터 패턴은 언어의 문법을 객체로 표현하여 해석하는 데 초점을 둡니다. 비슷한 행동 패턴으로는 컴포지트 패턴과 책임 연쇄 패턴이 있습니다.
- 컴포지트 패턴:
- 트리 구조를 생성하여 객체 간의 계층적 관계를 표현합니다. 인터프리터 패턴에서도 문법 트리를 구성할 때 컴포지트 패턴을 활용합니다.
- 책임 연쇄 패턴:
- 요청을 처리할 객체를 체인 형태로 연결하여 요청을 전달합니다. 인터프리터 패턴에서 입력을 처리하는 과정과 유사한 점이 있습니다.
마무리하며
인터프리터 패턴은 특정 도메인 언어를 해석하고 실행하는 데 적합한 디자인 패턴입니다. 간단한 문법 규칙을 구조화하고 객체로 표현하여 코드의 유연성과 확장성을 높일 수 있습니다. 그러나 복잡한 언어를 처리할 때는 성능 문제와 코드 복잡성이 증가할 수 있으므로 주의가 필요합니다.
도메인 특화 언어(DSL)나 간단한 규칙을 기반으로 작동하는 시스템을 설계할 때 인터프리터 패턴을 활용해보세요. 이를 통해 명확하고 확장 가능한 언어 처리기를 구현할 수 있습니다.
'Thinking > Concept' 카테고리의 다른 글
미디에이터 패턴(Mediator Pattern) 이해하기 (0) | 2024.11.16 |
---|---|
이터레이터 패턴(Iterator Pattern) 이해하기 (0) | 2024.11.16 |
커맨드 패턴(Command Pattern) 이해하기 (0) | 2024.11.16 |
책임 연쇄 패턴(Chain of Responsibility Pattern) 이해하기 (0) | 2024.11.16 |
프록시 패턴(Proxy Pattern) 이해하기 (0) | 2024.11.15 |