맨위로가기

인터프리터 패턴

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

인터프리터 패턴은 특정 언어의 문법을 나타내는 클래스를 정의하여, 주어진 언어의 문장을 해석하는 방법을 제공하는 디자인 패턴이다. 이 패턴은 UML 클래스 다이어그램을 통해 구조를 나타내며, Context, AbstractExpression, TerminalExpression, NonterminalExpression 등의 구성 요소로 이루어진다. 인터프리터 패턴은 SQL, 통신 프로토콜, 복잡한 비즈니스 규칙 처리, DSL 구현 등 다양한 분야에서 활용될 수 있으며, C#, Java, C++ 등의 프로그래밍 언어를 이용한 예시가 존재한다.

2. 구조

인터프리터 패턴은 `Context`, `AbstractExpression`, `TerminalExpression`, `NonterminalExpression` 등의 클래스로 구성된다.

인터프리터 패턴 UML 클래스 다이어그램


UML 클래스 다이어그램에서 `Client` 클래스는 표현식을 해석하기 위해 공통 `AbstractExpression` 인터페이스를 참조한다. `TerminalExpression` 클래스는 자식이 없으며 표현식을 직접 해석한다. `NonterminalExpression` 클래스는 자식 표현식의 컨테이너(`expressions`)를 유지 관리하고 이러한 `expressions`에 해석 요청(`interpret(context)`)을 전달한다.

객체 협업 다이어그램은 런타임 상호 작용을 보여준다. `Client` 객체는 추상 구문 트리에 해석 요청을 보낸다. 이 요청은 트리 구조의 모든 객체로 전달(수행)된다. `NonTerminalExpression` 객체(`ntExpr1, ntExpr2`)는 요청을 자식 표현식으로 전달한다. `TerminalExpression` 객체(`tExpr1, tExpr2, …`)는 해석을 직접 수행한다.

인터프리터 패턴의 구성 요소는 다음과 같다.

클래스설명
Context해석기가 사용하는 정보를 담고 있다.[1]
AbstractExpression모든 표현식에 공통으로 적용되는 인터페이스를 정의하며, `interpret()` 추상 메서드를 포함한다.[2]
TerminalExpression문법의 종단 기호에 해당하며, `interpret()` 메서드를 구현하여 문장을 해석한다.[1]
NonterminalExpression`AbstractExpression`을 상속받는 클래스 중 하나로, `Interpret()` 메서드는 "Called Nonterminal.Interpret()"를 출력한다.[2]


2. 1. UML 클래스와 객체 도표

none

  • -|]]

위의 UML 클래스 다이어그램에서 `Client` 클래스는 표현식을 해석하기 위해 공통 `AbstractExpression` 인터페이스를 참조한다. `interpret(context)`

`TerminalExpression` 클래스는 자식이 없으며 표현식을 직접 해석한다.

`NonTerminalExpression` 클래스는 자식 표현식의 컨테이너(`expressions`)를 유지 관리하고 이러한 `expressions`에 해석 요청을 전달한다.

객체 협업 다이어그램은 런타임 상호 작용을 보여준다. `Client` 객체는 추상 구문 트리에 해석 요청을 보낸다. 이 요청은 트리 구조의 모든 객체로 전달(수행)된다.

`NonTerminalExpression` 객체(`ntExpr1,ntExpr2`)는 요청을 자식 표현식으로 전달한다.

`TerminalExpression` 객체(`tExpr1,tExpr2,…`)는 해석을 직접 수행한다.

2. 2. 구성 요소

인터프리터 패턴은 다음 요소들로 구성된다.

  • AbstractExpression (추상 표현식): 모든 표현식에 공통으로 적용되는 인터페이스를 정의하며, `interpret()` 추상 메서드를 포함한다.[2]
  • TerminalExpression (종단 표현식): 문법의 종단 기호에 해당하는 표현식 클래스이다. `interpret()` 메서드를 구현하여 실제로 문장을 해석하는 역할을 한다.[1]
  • NonterminalExpression (비종단 표현식): `AbstractExpression`을 상속받는 클래스 중 하나이다. `Interpret()` 메서드를 호출하면 "Called Nonterminal.Interpret()"를 출력한다.[2]
  • Context (문맥): 해석기가 사용하는 정보를 담고 있는 클래스이다.


클래스설명C# 예제C++ 예제
Context해석기가 사용하는 정보를 담고 있다.[1]
AbstractExpression모든 표현식에 공통으로 적용되는 인터페이스를 정의하며, `interpret()` 추상 메서드를 포함한다.[2]해당 사항 없음
TerminalExpression문법의 종단 기호에 해당하며, `interpret()` 메서드를 구현하여 문장을 해석한다.[1]해당 사항 없음
NonterminalExpression`AbstractExpression`을 상속받는 클래스 중 하나로, `Interpret()` 메서드는 "Called Nonterminal.Interpret()"를 출력한다.[2]해당 사항 없음


2. 2. 1. Context

해석기가 사용하는 정보를 담고 있는 클래스이다. C# 코드 예제에서는 `Context` 클래스가 이 역할을 한다. C++ 코드 예제에서는 `Context` 클래스가 `VariableExp` 객체를 키로, `bool` 값을 값으로 갖는 맵을 사용하여 변수에 대한 값을 저장하고 조회하는 기능을 제공한다.[1]

C# 예제:

```csharp

class Context

{

}

```



C++ 예제:

```cpp

class Context {

public:

Context() :m() {}

bool lookup(const VariableExp* key) { return m.at(key); }

void assign(VariableExp* key, bool value) { m[key] = value; }

private:

std::map m;

};

```[1]

2. 2. 2. AbstractExpression

모든 표현식(Expression)에 공통으로 적용되는 인터페이스를 정의하며, `interpret()` 추상 메서드를 포함한다.[2]

C# 코드 예시:

```csharp

// "AbstractExpression"

abstract class AbstractExpression

{

public abstract void Interpret(Context context);

}

2. 2. 3. TerminalExpression

csharp

// "TerminalExpression"

class TerminalExpression : AbstractExpression

{

public override void Interpret(Context context)

{

Console.WriteLine("Called Terminal.Interpret()");

}

}

```

TerminalExpression은 문법의 종단 기호에 해당하는 표현식 클래스이다. `interpret()` 메서드를 구현하여 실제로 문장을 해석하는 역할을 한다.[1]

2. 2. 4. NonterminalExpression

csharp

// "NonterminalExpression"

class NonterminalExpression : AbstractExpression

{

public override void Interpret(Context context)

{

Console.WriteLine("Called Nonterminal.Interpret()");

}

}

```

NonterminalExpression은 AbstractExpression을 상속받는 클래스 중 하나이다. `Interpret()` 메서드를 호출하면 "Called Nonterminal.Interpret()"를 출력한다.[2]

3. 사용 예시

인터프리터 패턴은 특정 언어의 문법을 정의하고, 해당 언어의 문장을 해석하여 문제를 해결하는 방식이다.[2] 예를 들어, 복잡한 검색 표현식을 처리해야 할 때, 이를 클래스에 직접 구현(하드 코딩)하는 대신 인터프리터 패턴을 사용하면 유연성을 높일 수 있다. 즉, 클래스를 특정 표현식에 고정시키지 않고, 새로운 표현식을 추가하거나 기존 표현식을 변경하는 것이 가능해진다.[3]

인터프리터 패턴은 다음과 같은 경우에 유용하게 사용될 수 있다.[3]


  • SQL과 같은 데이터베이스 질의 언어
  • 통신 프로토콜을 기술하는 데 사용되는 특수 목적의 컴퓨터 언어


대한민국에서는 소프트웨어 개발의 다양한 영역에서 활용될 수 있는데, 예를 들어 복잡한 비즈니스 규칙을 처리하거나, 특정 도메인의 요구사항을 반영한 DSL을 구현하는 데 사용될 수 있다.

3. 1. C# 예제

csharp

// "Context"

class Context

{

}

// "AbstractExpression"

abstract class AbstractExpression

{

public abstract void Interpret(Context context);

}

// "TerminalExpression"

class TerminalExpression : AbstractExpression

{

public override void Interpret(Context context)

{

Console.WriteLine("Called Terminal.Interpret()");

}

}

// "NonterminalExpression"

class NonterminalExpression : AbstractExpression

{

public override void Interpret(Context context)

{

Console.WriteLine("Called Nonterminal.Interpret()");

}

}

class MainApp

{

static void Main()

{

var context = new Context();

// Usually a tree

var list = new List();

// Populate 'abstract syntax tree'

list.Add(new TerminalExpression());

list.Add(new NonterminalExpression());

list.Add(new TerminalExpression());

list.Add(new TerminalExpression());

// Interpret

foreach (AbstractExpression exp in list)

{

exp.Interpret(context);

}

}

}

3. 2. Java 예제

다음은 역폴란드 표기법을 사용하여 범용 프로그래밍 언어가 더 전문화된 언어를 해석하는 Java 예제이다.

입력:

'42 4 2 - +'는 44와 같다.

파서:

```java

import java.util.*;

interface Expression {

void interpret(Stack s);

}

class TerminalExpression_Number implements Expression {

private int number;

public TerminalExpression_Number(int number) { this.number = number; }

public void interpret(Stack s) { s.push(number); }

}

class TerminalExpression_Plus implements Expression {

public void interpret(Stack s) { s.push( s.pop() + s.pop() ); }

}

class TerminalExpression_Minus implements Expression {

public void interpret(Stack s) { s.push( -s.pop() + s.pop() ); }

}

class Parser {

private ArrayList parseTree = new ArrayList(); // 여기에는 하나의 비단말 표현식만 있다.

public Parser(String s) {

for (String token : s.split(" ")) {

if (token.equals("+")) parseTree.add( new TerminalExpression_Plus() );

else if (token.equals("-")) parseTree.add( new TerminalExpression_Minus() );

// ...

else parseTree.add( new TerminalExpression_Number(Integer.valueOf(token)) );

}

}

public int evaluate() {

Stack context = new Stack();

for (Expression e : parseTree) e.interpret(context);

return context.pop();

}

}

class InterpreterExample {

public static void main(String[] args) {

// 여기에서 위 식을 평가한다.

String expression = "42 4 2 - +";

Parser p = new Parser(expression);

System.out.println("'" + expression +"' equals " + p.evaluate());

}

}

3. 3. C++ 예제

cpp

#include

#include

#include

class Context;

class BooleanExp {

public:

BooleanExp() = default;

virtual ~BooleanExp() = default;

virtual bool evaluate(Context&) = 0;

virtual BooleanExp* replace(const char*, BooleanExp&) = 0;

virtual BooleanExp* copy() const = 0;

};

class VariableExp;

class Context {

public:

Context() :m() {}

bool lookup(const VariableExp* key) { return m.at(key); }

void assign(VariableExp* key, bool value) { m[key] = value; }

private:

std::map m;

};

class VariableExp : public BooleanExp {

public:

VariableExp(const char* name_) :name(nullptr) {

name = strdup(name_);

}

virtual ~VariableExp() = default;

virtual bool evaluate(Context& aContext) {

return aContext.lookup(this);

}

virtual BooleanExp* replace(const char* name_, BooleanExp& exp) {

if (0 == strcmp(name_, name)) {

return exp.copy();

} else {

return new VariableExp(name);

}

}

virtual BooleanExp* copy() const {

return new VariableExp(name);

}

VariableExp(const VariableExp&) = delete; // rule of three

VariableExp& operator=(const VariableExp&) = delete;

private:

char* name;

};

class AndExp : public BooleanExp {

public:

AndExp(BooleanExp* op1, BooleanExp* op2)

:operand1(nullptr), operand2(nullptr) {

operand1 = op1;

operand2 = op2;

}

virtual ~AndExp() = default;

virtual bool evaluate(Context& aContext) {

return operand1->evaluate(aContext) && operand2->evaluate(aContext);

}

virtual BooleanExp* replace(const char* name_, BooleanExp& exp) {

return new AndExp(

operand1->replace(name_, exp),

operand2->replace(name_, exp)

);

}

virtual BooleanExp* copy() const {

return new AndExp(operand1->copy(), operand2->copy());

}

AndExp(const AndExp&) = delete; // rule of three

AndExp& operator=(const AndExp&) = delete;

private:

BooleanExp* operand1;

BooleanExp* operand2;

};

int main() {

BooleanExp* expression;

Context context;

VariableExp* x = new VariableExp("X");

VariableExp* y = new VariableExp("Y");

expression = new AndExp(x, y);

context.assign(x, false);

context.assign(y, true);

bool result = expression->evaluate(context);

std::cout << result << '\n';

context.assign(x, true);

context.assign(y, true);

result = expression->evaluate(context);

std::cout << result << '\n';

}

```

```text

0

1

```

이 코드는 C++11을 사용하여 논리 표현식을 해석하는 인터프리터 패턴을 구현한 것이다. `BooleanExp` 추상 클래스는 논리 표현식의 기본 인터페이스를 정의한다. `VariableExp` 클래스는 변수를 나타내며, `AndExp` 클래스는 두 논리 표현식의 AND 연산을 나타낸다. `Context` 클래스는 변수와 값의 매핑을 저장하고, `evaluate` 메서드는 주어진 `Context`에서 논리 표현식의 값을 계산한다.

`main` 함수에서는 `X`와 `Y` 두 변수를 생성하고, `AndExp`를 사용하여 이 둘의 AND 연산을 수행하는 `expression`을 만든다. `context` 객체에 `X`는 `false`, `Y`는 `true`를 할당한 후 `expression`을 평가하면 `0`이 출력된다. 이후 `X`를 `true`로 변경하고 다시 평가하면 `1`이 출력된다.

4. 장점 및 고려사항

인터프리터 패턴은 새로운 문법 규칙을 추가하거나 기존 규칙을 변경하기 쉽게 만들어 준다는 장점이 있다. 그러나 문법이 복잡한 언어의 경우에는 클래스 계층 구조가 매우 복잡해질 수 있다는 단점도 있다.[2] 이러한 점을 고려하여, 인터프리터 패턴을 적용할 때 언어의 복잡성과 유지보수의 용이성을 균형 있게 고려해야 한다.

참조

[1] 서적 Design Patterns: Elements of Reusable Object-Oriented Software Addison-Wesley
[2] 서적 Design Patterns: Elements of Reusable Object-Oriented Software https://archive.org/[...] Addison Wesley
[3] 웹사이트 The Interpreter design pattern - Problem, Solution, and Applicability http://w3sdesign.com[...] 2017-08-12
[4] 웹사이트 The Interpreter design pattern - Structure and Collaboration http://w3sdesign.com[...] 2017-08-12
[5] 서적 Design Patterns: Elements of Reusable Object-Oriented Software Addison-Wesley
[6] 웹인용 The Interpreter design pattern - Structure and Collaboration http://w3sdesign.com[...] 2017-08-12



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com