티스토리 뷰

디자인 패턴

15. 인터프리터 패턴

jin-park 2022. 2. 10. 20:28

1. 의미

  • 인터프리터(interpreter) 사전적 의미 → 통역, 연주자
  • 자주 등장하는 문제를 간단한 언어로 정의하여 재사용하는 패턴
    • 반복되는 문제 패턴을 언어 또는 문법으로 정의하고 확장 
    • 패턴이나 언어, 문법등으로 정의하여 이슈 발생시 대입하여 사용
  • 정규식을 일종의 인터프리터로 본다.

다이어그램

  • context
    • 글로벌 변수, 모든 expression에서 사용되는 정보 
  • expression
    • interpret(context), context에 있는 값을 참조
    • 1. terminal expression
      • 자체 종료
    • 2. non terminal expression
      • 다른 expression을 참조해 봐야 결과를 확인, 다른 expression을 참조(재귀)
      • terminal 을 참조할 수 있고 다른 non terminal expression을 참조

2. 적용하기

2.1. 패턴 적용전

public class PostfixNotation {
 
    private final String expression;
 
    public PostfixNotation(String expression) {
        this.expression = expression;
    }
 
    public static void main(String[] args) {
        PostfixNotation postfixNotation = new PostfixNotation("123+-");
        // 자주 사용하는 문제
        // 123+- post fix를 사용하는 문자열
        postfixNotation.calculate();
    }
 
    private void calculate() {
        Stack<Integer> numbers = new Stack<>();
 
        for (char c : this.expression.toCharArray()) {
            switch (c) {
                case '+':
                    numbers.push(numbers.pop() + numbers.pop());
                    break;
                case '-':
                    int right = numbers.pop();
                    int left = numbers.pop();
                    numbers.push(left - right);
                    break;
                default:
                    numbers.push(Integer.parseInt(c + ""));
            }
        }
 
        System.out.println(numbers.pop());
    }
}

2.2. 인터프리터 패턴 적용 후

public interface PostfixExpression {
    int interpret(Map<Character, Integer> context);
}
public class VariableExpression implements PostfixExpression {
 
    private Character character;
 
    public VariableExpression(Character character) {
        this.character = character;
    }
 
    @Override
    public int interpret(Map<Character, Integer> context) {
        return context.get(this.character);
    }
}
public class PlusExpression implements PostfixExpression {
 
    private PostfixExpression left;
 
    private PostfixExpression right;
 
    public PlusExpression(PostfixExpression left, PostfixExpression right) {
        this.left = left;
        this.right = right;
    }
 
    @Override
    public int interpret(Map<Character, Integer> context) {
        return left.interpret(context) + right.interpret(context);
    }
}
public class MinusExpression implements PostfixExpression {
 
    private PostfixExpression left;
 
    private PostfixExpression right;
 
    public MinusExpression(PostfixExpression left, PostfixExpression right) {
        this.left = left;
        this.right = right;
    }
 
    @Override
    public int interpret(Map<Character, Integer> context) {
        return left.interpret(context) - right.interpret(context);
    }
}
public class MultiplyExpression implements PostfixExpression{
 
    private PostfixExpression left, right;
 
    public MultiplyExpression(PostfixExpression left, PostfixExpression right) {
        this.left = left;
        this.right = right;
    }
 
    @Override
    public int interpret(Map<Character, Integer> context) {
        return left.interpret(context) * right.interpret(context);
    }
}
public class PostfixParser {
 
    public static PostfixExpression parse(String expression) {
        Stack<PostfixExpression> stack = new Stack<>();
        for (char c : expression.toCharArray()) {
            stack.push(getExpression(c, stack));
        }
        return stack.pop();
    }
 
    private static PostfixExpression getExpression(char c, Stack<PostfixExpression> stack) {
        switch (c) {
            case '+':
                return new PlusExpression(stack.pop(), stack.pop());
            case '-':
                PostfixExpression right = stack.pop();
                PostfixExpression left = stack.pop();
                return new MinusExpression(left, right);
            default:
                return new VariableExpression(c);
        }
    }
}
public static void main(String[] args) {
    PostfixExpression expression = PostfixParser.parse("xyz+-a+");
    int result = expression.interpret(Map.of('x', 1, 'y', 2, 'z', 3, 'a', 4));
    System.out.println(result);
}

3. 장단점

3.1. 장점

  • 자주 등장하는 문제 패턴을 언어와 문법으로 정의할 수 있다
  • 기존 코드를 변경하지 않고 새로운 expression을 추가할 수 있다
  • expression이 본인의 기능인 하나의 기능만한다
    • SRP (Single Responsibility Principle)

3.2. 단점

  • 복잡한 문법을 표현하려면 expression  parser 복잡해진다

'디자인 패턴' 카테고리의 다른 글

17. 중재자 패턴  (0) 2022.02.10
16. 이터레이터 패턴  (0) 2022.02.10
14. 커맨드 패턴  (0) 2022.02.10
13. 책임연쇄패턴  (0) 2022.02.10
12. 프록시 패턴  (0) 2022.02.10
댓글