Contents
문장을 해석할 때 사용하는 패턴. 해석기, 즉 간이언어를 만들기 위한 패턴. 언어 문법이나 표현을 평가할 수 있는 방법을 제공.
(행동패턴)
특정 컨텍스트를 해석하도록 지시하는 표현 인터페이스를 구현하는 것도 포함. 이 패턴은 SQL구문분석, 기호처리엔진 등에 사용됨.
-> 쉽게 말해, 사용자가 원하는 다양한 명령을 쉽게 표현할 수 있게 구문 약속을 해야함. 그리고, 해석자에서는 이와 같이 약속된 구문을 입력 인자로 전달되었을 때 이를 해석을 할 수 있어야 합니다.
ex) "2 add 3" 과 같은 표현은 피연산자:2, 연산자: +, 피연산자:3 으로 해석될 수 있다는 것.
사용자가 다양한 명령을 쉬운 표현 방법으로 전달할 수 있다. 하지만, 너무 많은 명령에 대한 조합에 대해 해석자 패턴을 적용한다면 정규화 과정에 들어가는 비용이 기하급수적으로 커질 수 있으므로 그렇다면 다른 방법을 사용하는게 좋음!!!
ex) 정규표현식
문자열에서 어떤 패턴을 찾는 알고리즘을 매번 작성하는 것보다는 발견할 문자열을 정의하는 정규 표현식을 해석하는 알고리즘을 만드는 것이 더 낫다!! -> 정규표현식
언제 사용하는 것이 좋을까?
- 정의할 언어의 문법이 간단할 때
( 문법이 복잡하면 관리할 클래스가 많아져 복잡해짐)
- 성능이 중요한 문제가 되지 않을 때
* 추상구문트리 (Abstarct Sytax Tree)
고급 언어를 기계어로 번역할 때 트리 구조를 통해 표현
' a+b*c+d'를 표현할 때 AST라는 트리구조를 사용해 문장정보를 나누고, 평가의 순서를 정할 수 있다.
결과
- 문법의 변경과 확장이 쉽다 : 상속 이용
- 문법 구현이 용이 : 노드에 해당되는 클래스들은 비슷한 구현방법을 갖기 때문에 이들 클래스를 작성하는 것이 쉬움
- 복잡한 문법은 관리하기 어려움 : 많은 규칙을 포함한 문법은 관리, 유지 어려움 -> 컴파일러 생성기나 파서 생성기 이용하는 것이 좋음
예제)
package interpreter;
public interface Expression {
public boolean interpret(String context);
}
package interpreter;
public class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data) {
this.data=data;
}
@Override
public boolean interpret(String context) {
if(context.contains(data)) return true;
return false;
}
}
package interpreter;
public class OrExpression implements Expression {
private Expression exp1 =null;
private Expression exp2 = null;
public OrExpression(Expression exp1, Expression exp2) {
this.exp1 = exp1;
this.exp2 = exp2;
}
@Override
public boolean interpret(String context) {
return exp1.interpret(context)||exp2.interpret(context);
}
}
package interpreter;
public class AndExpression implements Expression {
private Expression exp1 =null;
private Expression exp2 = null;
public AndExpression(Expression exp1, Expression exp2) {
this.exp1 = exp1;
this.exp2 = exp2;
}
@Override
public boolean interpret(String context) {
return exp1.interpret(context)&&exp2.interpret(context);
}
}
package interpreter;
public class InterpreterPatternDemo {
//규칙을 생성하고 그것을 파싱하기 위해 Expression클래스를 사용한다
//Rule : Robert and John are male
public static Expression getMaleExpression() {
Expression robert=new TerminalExpression("Robert");
Expression john = new TerminalExpression("John");
return new OrExpression(robert, john);
}
//Rule : Julie is a married women
public static Expression getMarriedWomanExpression() {
Expression Julie =new TerminalExpression("Julie");
Expression married =new TerminalExpression("married");
return new AndExpression(Julie,married);
}
public static void main(String[] args) {
Expression isMale=getMaleExpression();
Expression isMarriedWoman=getMarriedWomanExpression();
System.out.println("John is male? "+isMale.interpret("John"));
System.out.println("Julie is a married women? "+isMarriedWoman.interpret("Julie married"));
}
}
>> Client는 문장해석의 주체이면서 인터프리터를 Context에 대해 적용
Context는 interpreter의 전역정보를 가지고 있다.
아래 그림을 보면 TerminalExpression과 NonterminalExpression이 존재한다. 트리구조를 생각하면 편하다.
표현식안에 다른 표현식(자식 노드가 있다면)에는 다시 평가를 수행해야 한다.
[참고]
'IT 공부 > 디자인패턴' 카테고리의 다른 글
[디자인패턴] State Pattern 상태패턴 (0) | 2019.05.02 |
---|