본문 바로가기

Design Pattern

[Design Pattern] 24. Interpreter Pattern(인터프리터 패턴) C#

728x90

자신의 문법을 정의하고 인터프리터 객체를 사용하여 문법을 분석하여 출력하는 디자인 패턴입니다.

행동 패턴(Behavioral Design Patterns) 중 하나입니다.

 

 

장점

  • 새로운 표현(문법)을 추가할 수 있기 때문에 확장 및 수정이 수월할  있습니다.
  • 언어 또는 문법을 개체 지향 트리 구조로 나타낼 수 있으므로 이해 및 유지 관리가 더 쉬워집니다.
  • 언어나 문법에 따라 작동하는 복잡한 규칙이나 알고리즘을 더 쉽게 구현할 수 있습니다.

단점

  • 복잡한 언어나 문법의 경우 구현하기가 복잡할 수 있습니다.
  • 언어나 문법을 나타내는 트리 구조를 생성해야 하므로 다른 방식보다 안좋 수 있습니다.
  • 트리 구조의 다양한 곳에서 오류가 발생할 수 있으므로 디버깅하기 어려울 수 있습니다.

 

C#으로 Console 프로젝트를 하나 생성해서 할 것입니다.

 

기본적으로 상당히 복잡한 패턴입니다.

복잡하고 부피가 큰 패턴이죠. 최대한 간단하게 만들어 보겠습니다.

목표는 Main에서 string으로 된 더하기 혹은 빼기 수식을 넘기고 그 결과를 출력해보겠습니다.

 

프로젝트의 tree구조는 아래와 같습니다.

StrategyPattern (Project)

|- Program.cs (Main)

|- IExpression.cs (Expression Interface)

|- Number.cs (Concreate Expression)

|- Add.cs (Concreate Expression)

|- Subtract.cs (Concreate Expression)

|- Interpreter.cs (Interpreter)




IExpression.cs

namespace Interpreter
{
    public interface IExpression
    {
        int Calculate();
    }
}

계산해주는 함수를 하나 구성해줍니다.


Number.cs

namespace Interpreter
{
    public class Number : IExpression
    {
        private readonly int number;

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

        public int Calculate()
        {
            return number;
        }
    }
}

숫자를 가지고 있는 클래스입니다.

계산해도 숫자 그대로 반환합니다.


Add.cs

namespace Interpreter
{
    public class Add : IExpression
    {
        private readonly IExpression first;
        private readonly IExpression second;

        public Add(IExpression first, IExpression second)
        {
            this.first = first;
            this.second = second;
        }

        public int Calculate()
        {
            return first.Calculate() + second.Calculate();
        }
    }
}

더해주는 연산자로 쓰일 클래스입니다.

계산 시 가지고 있는 Expression의 각 연산 결과를 더해 리턴합니다.


Subtract.cs

namespace Interpreter
{
    public class Subtract : IExpression
    {
        private readonly IExpression first;
        private readonly IExpression second;

        public Subtract(IExpression first, IExpression second)
        {
            this.first = first;
            this.second = second;
        }

        public int Calculate()
        {
            return first.Calculate() - second.Calculate();
        }
    }
}

Subtract클래스의 경우는 Add에서 결과를 빼서 리턴해줍니다.


Interpreter.cs

using System;

namespace Interpreter
{
    public class Interpreter
    {
        public int Interpret(string input)
        {
            string[] tokens = input.Split(' ');

            IExpression result;
            IExpression first = new Number(int.Parse(tokens[0]));
            IExpression second = new Number(int.Parse(tokens[2]));
            string operation = tokens[1];

            switch (operation)
            {
                case "+":
                    result = new Add(first, second);
                    break;
                case "-":
                    result = new Subtract(first, second);
                    break;
                default:
                    throw new ArgumentException("Invalid");
            }

            return result.Calculate();
        }
    }
}

interpreter클래스는 string을 하나 받아 그 문자열을 분석해 연산한 뒤 결과를 리턴하게 만들어줍니다.

보시면 ' '로 split하고 숫자와 연산자를 구별해 연산한 뒤 리턴함을 확인할 수 있습니다.


Program.cs

using System;

namespace Interpreter
{
    class Program
    {
        static void Main(string[] args)
        {
            Interpreter interpreter = new Interpreter();

            Console.WriteLine("20 + 7 = " + interpreter.Interpret("20 + 7"));
            Console.WriteLine("16 - 54 = " + interpreter.Interpret("16 - 54"));
        }
    }
}

Interpreter를 하나 만들고 연산하고 싶은 수식(string)을 넣어줍니다.

아래의 이미지와 같이 원하는대로 출력됨을 확인할 수 있습니다.

 

 

실행 결과

 

트리 구조로 만들고 Interpreter 클래스를 좀 더 구현해주면 더 확장할 수 있습니다.

프로그램의 크기가 커질 수 있고 코드가 많이 늘어나는거 빼면 필요한 경우 유용하게 사용하실 수 있습니다.

정규식(regex)가 대표적인 예시겠네요.