인터프리터 패턴
1. 개요
인터프리터 패턴은 특정 언어의 문법을 나타내는 클래스를 정의하여, 주어진 언어의 문장을 해석하는 방법을 제공하는 디자인 패턴이다. 이 패턴은 UML 클래스 다이어그램을 통해 구조를 나타내며, Context, AbstractExpression, TerminalExpression, NonterminalExpression 등의 구성 요소로 이루어진다. 인터프리터 패턴은 SQL, 통신 프로토콜, 복잡한 비즈니스 규칙 처리, DSL 구현 등 다양한 분야에서 활용될 수 있으며, C#, Java, C++ 등의 프로그래밍 언어를 이용한 예시가 존재한다.
-
소프트웨어 디자인 패턴 -
모델-뷰-컨트롤러
모델-뷰-컨트롤러(MVC)는 소프트웨어 디자인 패턴으로, 응용 프로그램을 모델, 뷰, 컨트롤러 세 가지 요소로 분리하여 개발하며, 사용자 인터페이스 개발에서 데이터, 표현 방식, 사용자 입력 처리를 분리해 유지보수성과 확장성을 높이는 데 기여한다. -
소프트웨어 디자인 패턴 -
스케줄링 (컴퓨팅)
스케줄링은 운영 체제가 시스템의 목적과 환경에 맞춰 작업을 관리하는 기법으로, 장기, 중기, 단기 스케줄러를 통해 프로세스를 선택하며, CPU 사용률, 처리량 등을 기준으로 평가하고, FCFS, SJF, RR 등의 알고리즘을 사용한다.
2. 구조
인터프리터 패턴은 `Context`, `AbstractExpression`, `TerminalExpression`, `NonterminalExpression` 등의 클래스로 구성된다.
위 UML 클래스 다이어그램에서 `Client` 클래스는 표현식을 해석하기 위해 공통 `AbstractExpression` 인터페이스를 참조한다. `TerminalExpression` 클래스는 자식이 없으며 표현식을 직접 해석한다. `NonterminalExpression` 클래스는 자식 표현식의 컨테이너(`expressions`)를 유지 관리하고 이러한 `expressions`에 해석 요청(`interpret(context)`)을 전달한다.
객체 협업 다이어그램은 런타임 상호 작용을 보여준다. `Client` 객체는 추상 구문 트리에 해석 요청을 보낸다. 이 요청은 트리 구조의 모든 객체로 전달(수행)된다. `NonTerminalExpression` 객체(`ntExpr1, ntExpr2`)는 요청을 자식 표현식으로 전달한다. `TerminalExpression` 객체(`tExpr1, tExpr2, …`)는 해석을 직접 수행한다.
인터프리터 패턴의 구성 요소는 다음과 같다.
2.1. UML 클래스와 객체 도표
--|]]
위의 UML 클래스 다이어그램에서 `Client` 클래스는 표현식을 해석하기 위해 공통 `AbstractExpression` 인터페이스를 참조한다. `interpret(context)`
`TerminalExpression` 클래스는 자식이 없으며 표현식을 직접 해석한다.
`NonTerminalExpression` 클래스는 자식 표현식의 컨테이너(`expressions`)를 유지 관리하고 이러한 `expressions`에 해석 요청을 전달한다.
객체 협업 다이어그램은 런타임 상호 작용을 보여준다. `Client` 객체는 추상 구문 트리에 해석 요청을 보낸다. 이 요청은 트리 구조의 모든 객체로 전달(수행)된다.
`NonTerminalExpression` 객체(`ntExpr1,ntExpr2`)는 요청을 자식 표현식으로 전달한다.
`TerminalExpression` 객체(`tExpr1,tExpr2,…`)는 해석을 직접 수행한다.
2.2. 구성 요소
인터프리터 패턴은 다음 요소들로 구성된다.
* AbstractExpression (추상 표현식): 모든 표현식에 공통으로 적용되는 인터페이스를 정의하며, `interpret()` 추상 메서드를 포함한다.
* TerminalExpression (종단 표현식): 문법의 종단 기호에 해당하는 표현식 클래스이다. `interpret()` 메서드를 구현하여 실제로 문장을 해석하는 역할을 한다.
* NonterminalExpression (비종단 표현식): `AbstractExpression`을 상속받는 클래스 중 하나이다. `Interpret()` 메서드를 호출하면 "Called Nonterminal.Interpret()"를 출력한다.
* Context (문맥): 해석기가 사용하는 정보를 담고 있는 클래스이다.
2.2.1. Context
해석기가 사용하는 정보를 담고 있는 클래스이다. C# 코드 예제에서는 `Context` 클래스가 이 역할을 한다. C++ 코드 예제에서는 `Context` 클래스가 `VariableExp` 객체를 키로, `bool` 값을 값으로 갖는 맵을 사용하여 변수에 대한 값을 저장하고 조회하는 기능을 제공한다.
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
};
```
2.2.2. AbstractExpression
모든 표현식(Expression)에 공통으로 적용되는 인터페이스를 정의하며, `interpret()` 추상 메서드를 포함한다.
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()` 메서드를 구현하여 실제로 문장을 해석하는 역할을 한다.
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()"를 출력한다.
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
}
class TerminalExpression_Number implements Expression {
private int number;
public TerminalExpression_Number(int number) { this.number = number; }
public void interpret(Stack
}
class TerminalExpression_Plus implements Expression {
public void interpret(Stack
}
class TerminalExpression_Minus implements Expression {
public void interpret(Stack
}
class Parser {
private 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
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