자신의 문법을 정의하고 인터프리터 객체를 사용하여 문법을 분석하여 출력하는 디자인 패턴입니다.
행동 패턴(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)가 대표적인 예시겠네요.
'Design Pattern' 카테고리의 다른 글
[Design Pattern] 23. Builder Pattern(빌더 패턴) C# (0) | 2023.04.12 |
---|---|
[Design Pattern] 22. Prototype Pattern(프로토타입 패턴) C# (0) | 2023.04.11 |
[Design Pattern] 21. Abstract Factory Pattern(추상 팩토리 패턴) C# (0) | 2023.04.10 |
[Design Pattern] 20. Factory Method Pattern(팩토리 메소드 패턴) C# (0) | 2023.04.09 |
[Design Pattern] 19. Singleton Pattern(싱글톤 패턴) C# (0) | 2023.04.08 |