본문 바로가기
Thinking/Concept

인터프리터 패턴(Interpreter Pattern) 이해하기

by Dev_카페인 2024. 11. 16.
반응형

인터프리터 패턴(Interpreter Pattern) 이해하기

인터프리터 패턴언어의 문법을 정의하고, 해당 언어의 문장을 해석하고 실행하는 인터프리터를 구현하기 위한 행동 디자인 패턴입니다. 이 패턴은 주로 **특정 도메인에 특화된 언어(Domain-Specific Language, DSL)**를 처리하거나, 복잡한 표현식을 평가하는 데 사용됩니다.

인터프리터 패턴은 언어의 문법 구조를 객체로 표현하여, 문법을 기반으로 입력을 해석하고 실행할 수 있는 구조를 제공합니다. 이번 포스트에서는 인터프리터 패턴의 개념과 구조, 구현 방법, 장단점 및 사용 사례를 구체적인 예제와 함께 살펴보겠습니다.

인터프리터 패턴이란?

인터프리터 패턴은 간단한 언어의 문법을 정의하고 이를 해석하는 클래스를 구현하기 위한 디자인 패턴입니다. 이 패턴은 문법 규칙을 기반으로 입력을 해석하고, 해당 규칙을 구현한 객체들을 통해 문장을 평가하거나 실행할 수 있도록 합니다.

주요 개념은 언어의 문법을 객체로 표현하는 것으로, 각 문법 규칙에 해당하는 클래스를 만들어 트리 형태로 구성한 뒤, 이를 통해 문장을 해석합니다.

 

인터프리터 패턴의 구조

인터프리터 패턴의 기본 구조는 다음과 같습니다.

  1. AbstractExpression (추상 표현식):
    • 문법 규칙을 정의하는 공통 인터페이스로, 모든 구체적 표현식 클래스가 구현해야 할 메서드를 정의합니다.
  2. TerminalExpression (종결 표현식):
    • 문법의 단말 기호(기본 규칙)에 해당하는 클래스입니다. 주어진 입력을 해석하여 결과를 반환합니다.
  3. NonTerminalExpression (비종결 표현식):
    • 문법의 비단말 기호(복합 규칙)에 해당하는 클래스입니다. 다른 표현식을 포함하여 더 복잡한 규칙을 처리합니다.
  4. Context (문맥):
    • 해석 중에 필요한 정보를 제공하는 클래스입니다. 문장을 해석하기 위해 필요한 데이터를 유지하거나 전달합니다.
  5. Client (클라이언트):
    • 문법 구조를 생성하고 해석기를 실행하는 사용자입니다.

인터프리터(Interpreter)

인터프리터 패턴의 구현 방법

예제 코드: 간단한 산술 표현식 해석기

다음은 산술 표현식(예: "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

설명

  1. TerminalExpression:
    • NumberExpression 클래스는 숫자를 해석하는 종결 표현식입니다. 숫자를 그대로 반환합니다.
  2. NonTerminalExpression:
    • AddExpression과 SubtractExpression 클래스는 덧셈과 뺄셈을 해석하는 비종결 표현식입니다. 각각 좌측과 우측 표현식을 해석한 결과를 더하거나 뺍니다.
  3. Client:
    • 클라이언트 코드에서 표현식을 트리 형태로 구성한 뒤, 최상위 표현식의 Interpret() 메서드를 호출하여 전체 표현식을 평가합니다.

 

인터프리터 패턴의 장단점

장점

  1. 언어 구조화:
    • 간단한 언어의 문법을 명확하게 구조화하고 객체로 표현할 수 있습니다.
  2. 확장성:
    • 새로운 문법 규칙이 추가되더라도, 새로운 표현식 클래스를 추가하면 기존 코드를 수정하지 않고 확장할 수 있습니다.
  3. 유연성:
    • 표현식을 트리 형태로 구성하여 복잡한 문법 구조를 처리할 수 있습니다.

단점

  1. 복잡성 증가:
    • 문법 규칙이 많아질수록 표현식 클래스가 많아져 코드가 복잡해질 수 있습니다.
  2. 성능 문제:
    • 트리를 반복적으로 탐색하면서 표현식을 해석하므로, 성능이 중요한 상황에서는 부적합할 수 있습니다.
  3. 현실적인 제한:
    • 복잡한 언어(예: 프로그래밍 언어 전체)를 처리하기에는 인터프리터 패턴이 비효율적일 수 있습니다.

 

언제 인터프리터 패턴을 사용해야 할까?

인터프리터 패턴은 다음과 같은 상황에서 유용합니다.

  1. 도메인 특화 언어(DSL)를 처리해야 할 때:
    • 간단한 규칙이나 표현식을 가진 언어를 해석하고 실행해야 할 때.
  2. 문법 구조가 자주 변경되거나 확장될 때:
    • 문법이 자주 변경되거나 새로운 규칙이 추가되는 환경에서 유연하게 대처할 수 있습니다.
  3. 단순한 문법 구조를 처리할 때:
    • 복잡한 문법보다는 간단한 규칙을 기반으로 작동하는 언어를 처리하기에 적합합니다.

 

인터프리터 패턴과 관련 패턴 비교

인터프리터 패턴은 언어의 문법을 객체로 표현하여 해석하는 데 초점을 둡니다. 비슷한 행동 패턴으로는 컴포지트 패턴책임 연쇄 패턴이 있습니다.

  • 컴포지트 패턴:
    • 트리 구조를 생성하여 객체 간의 계층적 관계를 표현합니다. 인터프리터 패턴에서도 문법 트리를 구성할 때 컴포지트 패턴을 활용합니다.
  • 책임 연쇄 패턴:
    • 요청을 처리할 객체를 체인 형태로 연결하여 요청을 전달합니다. 인터프리터 패턴에서 입력을 처리하는 과정과 유사한 점이 있습니다.

 

마무리하며

인터프리터 패턴은 특정 도메인 언어를 해석하고 실행하는 데 적합한 디자인 패턴입니다. 간단한 문법 규칙을 구조화하고 객체로 표현하여 코드의 유연성과 확장성을 높일 수 있습니다. 그러나 복잡한 언어를 처리할 때는 성능 문제와 코드 복잡성이 증가할 수 있으므로 주의가 필요합니다.

도메인 특화 언어(DSL)나 간단한 규칙을 기반으로 작동하는 시스템을 설계할 때 인터프리터 패턴을 활용해보세요. 이를 통해 명확하고 확장 가능한 언어 처리기를 구현할 수 있습니다.

반응형