Skip to main content

[Design Pattern] 행동 패턴 10. 인터프리터 (Interpreter)




인터프리터 패턴 #

인터프리터

  • 어떤 언어에 대해 그 언어의 문법에 대한 표현을 정의하면서, 그 표현을 사용하여 해당 언어로 기술된 문장을 해석하는 해석자를 함께 정의한다.
  • 단점
    • 객체를 많이 만들어야 하고, 포인터에 많은 메모리를 소모한다.
    • 또한 하위 표현식에 접근해야 하므로 데이터 캐시에 치명적이다.
    • 이렇게 느리고 메모리가 많이 필요하기 때문에 대부분의 프로그래밍 언어는 이 패턴을 쓰진 않는다.

수식 표현식 예시 #

$$ (1 + 2) * (3 - 4)$$

  • 인터프리터 패턴은 위와 같은 표현식을 추상 구문 트리로 만들고 실행 시에는 자기 자신을 해석(평가) 하게 한다.
class Expression
{
public:
  virtual ~Expression() {}
  
  // 표현식은 자기 자신을 평가한다. 
  virtual double evaluate() = 0; 
};

class NumberExpression : public Expression
{
private:
  double value;

public:
  NumberExpression(double v) : value(v) {}
  
  // 숫자는 자기 값을 그대로 평가한다. 
  virtual double evaluate() 
  { 
    return value;
  }
};

class AdditionExpression : public Expression
{
private:
  Expression* left;
  Expression* right;

public:
  AdditionExpression(Expression* l, Expression* r) : left(l), right(r) {}
  
  // 더하기는 하위표현식을 재귀적으로 평가해서 더한다. 
  virtual double evaluate()
  {
    double l = left->evaluate();
    double r = right->evaluate();
    return l + r;
  }
};

void use()
{
  NumberExpression a(1);
  NumberExpression b(2);
  AdditionExpression add(&a, &b);
  add.evalute();
}

개념적인 예시 #

// 표현식 
public interface IExpression 
{
  bool Interpret(string context);
}

public class TerminalExpression : IExpression 
{
  private string data;

  public TerminalExpression(string data)
  {
    this.data = data;
  }

  // 해당 표현을 해석한다
  public override bool Interpret(string context) 
  {
    if (context.contains(data))
    {
      return true;
    }
    return false;
  }
}

public class AndExpression : IExpression 
{
  private IExpression expr1 = null;
  private IExpression expr2 = null;

  public AndExpression(IExpression expr1, IExpression expr2) 
  {
    this.expr1 = expr1;
    this.expr2 = expr2;
  }

  public override bool Interpret(string context) 
  {
    return expr1.Interpret(context) && expr2.Interpret(context);
  }
}

public class OrExpression : IExpression 
{
  private IExpression expr1 = null;
  private IExpression expr2 = null;

  public OrExpression(IExpression expr1, IExpression expr2) 
  {
    this.expr1 = expr1;
    this.expr2 = expr2;
  }

  public override bool Interpret(string context) 
  {
    return expr1.Interpret(context) || expr2.Interpret(context);
  }
}

class Program
{
  static void Main(string[] args)
  {
    // 표현들
    IExpression robert = new TerminalExpression("Robert");
    IExpression john = new TerminalExpression("John");
    IExpression julie = new TerminalExpression("Julie");
    IExpression Married = new TerminalExpression("Married");
    
    IExpression isMale = new OrExpression(robert, john);
    IExpression isMarriedWoman = new AndExpression(julie, married);
    
    // 컨텍스트 
    string context1 = "John";
    string context2 = "Married Julie";
    
    // 컨텍스트를 표현에 따라 해석한다. 
    Console.WriteLine("John is male? " + isMale.Interpret(context1)); // true
    Console.WriteLine("Julie is a married women? " + isMarriedWoman.Interpret(context2)); // true
  }
}



References #