Featured image of post 14. 다양한 패턴 빠르게 알아보기 - 인터프리터 패턴

14. 다양한 패턴 빠르게 알아보기 - 인터프리터 패턴

헤드 퍼스트 디자인 패턴

인터프리터(Interpreter) 패턴

어떤 언어의 인터프리터를 만들 때는 인터프리터 패턴을 사용한다.

인터프리터 패턴은 언어나 문법 규칙을 해석하거나 해석해기 위한 디자인 패턴으로, 주로 언어 해석기를 구현하는 데 사용된다.

주어진 언어의 문법 규칙을 클래스로 표현하고, 이를 해석하여 실행하는 구조를 제공한다.

특징

간단한 언어를 구현할 때 인터프리터 패턴이 유용하게 쓰인다.

효율보다는 단순하고 간단하게 문법을 만드는 것이 더 중요한 경우에 유용하다.

  • 언어 해석
    • 특정 언어의 문법을 객체로 표현하고 이를 해석하여 실행한다.
  • 문법 구조 분리
    • 문법의 구조를 표현식 클래스에 캡슐화하여 각 표현식을 독립적으로 변경 가능하도록 한다.

구성 요소

인터프리터 패턴 구조

  • AbstractExpression(추상 표현식)
    • 인터프리터 패턴의 인터페이스를 정의
    • 문법 규칙에 해당하는 각 표현식이 해당 인터페이스를 구현한다.
  • TerminalExpression(종단 표현식)
    • 구체적인 표현식으로, 더 이상 나뉠 수 없는 최소 단위의 표현식을 나타낸다.
  • NonterminalExpression(비종단 표현식)
    • 여러 종단 표현식을 조합하여 복잡한 표현식을 나타낸다.
  • Context
    • 해석기가 해석할 문맥 정보 제공
  • Client
    • 구체적인 표현식을 조합하여 컨텍스트에 표현식을 해석하도록 요청하는 역할 수행

예시

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// AbstractExpression
public interface Expression {
    int interpret(Context context);
}

// TerminalExpression
public class NumberExpression implements Expression {
    private int number;

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

    @Override
    public int interpret(Context context) {
        return number;
    }
}

// NonterminalExpression
public class AddExpression implements Expression {
    private Expression left;
    private Expression right;

    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) + right.interpret(context);
    }
}

// Context
public class Context {
    private String input;
    private int output;

    public Context(String input) {
        this.input = input;
    }

    public String getInput() {
        return input;
    }

    public void setInput(String input) {
        this.input = input;
    }

    public int getOutput() {
        return output;
    }

    public void setOutput(int output) {
        this.output = output;
    }
}

// Client
public class Client {
    public static void main(String[] args) {
        // 예시: 1 + 2
        Expression expression = new AddExpression(new NumberExpression(1), new NumberExpression(2));

        Context context = new Context("1 + 2");
        int result = expression.interpret(context);

        System.out.println(context.getInput() + " = " + result);
    }
}

장단점

장점

  • 유연한 확장성
    • 문법을 클래스로 표현해서 쉽게 언어를 구현할 수 있다.
    • 문법이 클래스로 표현되므로 언어를 쉽게 변경하거나 확장할 수 있다.
    • 클래스 구조에 메소드만 추가하면 프로그램을 해석하는 기본 기능 외에 예쁘게 출력하는 기능이나 더 나은 프로그램 확인 기능 같은 새로운 기능을 추가할 수 있다.
  • 문법 구조 분리
    • 문법의 구조를 표현식 클래스에 캡슐화하여 각 표현식을 독립적으로 변경할 수 있다.

단점

  • 복잡한 문법 구조
    • 복잡한 문법에 대해 클래스 수가 증가할 수 있다.
    • 이러한 경우 파서나 컴파일러 생성기를 쓰는 편이 낫다.
  • 성능
    • 큰 문장을 해석할 경우 성능에 영향을 미칠 수 있다.