🎈 인터프리터 패턴 (Interpreter Pattern)
• 주로 문장 해석하는 목적으로 사용되는 패턴
• 정규 표현식, SQL 구문, 컴파일러 구현에 활용됨
• 디자인 패턴 중 행위 패턴에 해당된다.
💻 디자인 패턴(Design Pattern)이란?
👨💻 디자인 패턴(Design Pattern)이란? • SW 개발 방법 중에서도 구조적인 문제 해결에 목적을 둔다. • 알고리즘과 같이 특정 문제를 해결하는 Logic 형태보다는 특정 상황에 적용할 수 있는 방
zoosso.tistory.com
[예제 코드]
#include <iostream>
class Expression {
public:
virtual int interpret() = 0;
};
class Number : public Expression {
private:
int value;
public:
Number(int val) : value(val) {}
int interpret() override {
return value;
}
};
class Add : public Expression {
private:
Expression* left;
Expression* right;
public:
Add(Expression* l, Expression* r) : left(l), right(r) {}
int interpret() override {
return left->interpret() + right->interpret();
}
};
int main() {
Expression* expression = new Add(new Number(5), new Number(3));
int result = expression->interpret();
std::cout << "5 + 3 = " << result << std::endl;
return 0;
}
인터프리터 패턴 형태를 위한 쉬운 예제로
다양한 유형의 수식을 위한 클래스 확장을 쉽게 해볼 수 있다.
(단순 덧셈 연산에서 복잡하게 패턴을 적용해야 하나 싶을 것이다.)
[예제 코드] - 인터프리터 패턴 적용 X
#include <iostream>
#include <string>
bool lookupVariable(const std::string& var) {
if (var == "A") return true;
if (var == "B") return false;
return false;
}
bool evaluateExpression(const std::string& expression) {
bool ret = false;
if (expression == "A AND B") {
ret = lookupVariable("A") && lookupVariable("B");
std::cout << "A AND B " << std::endl;
}
else if (expression == "NOT A") {
ret = !lookupVariable("A");
std::cout << "NOT A " << std::endl;
}
else if (expression == "A OR B AND A") {
ret = lookupVariable("A") || lookupVariable("B") && lookupVariable("A");
std::cout << "A OR B AND A " << std::endl;
}
else
{
std::cout << "등록되지 않은 수식!" << std::endl;
}
return ret;
}
int main() {
std::string expression = "A AND B";
bool result = evaluateExpression(expression);
std::cout << "Result: " << (result ? "True" : "False") << std::endl;
puts("\n");
expression = "A OR B AND A";
result = evaluateExpression(expression);
std::cout << "Result: " << (result ? "True" : "False") << std::endl;
return 0;
}
A, B는 변수로 예제에서는 단순하게 true/false로 바로 처리하였다.
→ 새로운 수식(espression)이 추가되면
evaluateExpression 함수에서 if/else 코드 변경이 필요하다.
→ 표현식을 재귀적으로 처리하기도 복잡해 보인다.
#include <iostream>
#include <string>
#include <map>
class Context {
public:
bool lookupVariable(const std::string& var) {
if (var == "A") return true;
if (var == "B") return false;
// 다른 변수 처리 추가 가능
return false;
}
};
class Expression {
public:
virtual bool interpret(Context& context) = 0;
};
class Variable : public Expression {
private:
std::string name;
public:
Variable(const std::string& varName) : name(varName) {}
bool interpret(Context& context) override {
return context.lookupVariable(name);
}
};
class AndExpression : public Expression {
private:
Expression* left;
Expression* right;
public:
AndExpression(Expression* l, Expression* r) : left(l), right(r) {}
bool interpret(Context& context) override {
std::cout << "AND 연산" << std::endl;
return left->interpret(context) && right->interpret(context);
}
};
class OrExpression : public Expression {
private:
Expression* left;
Expression* right;
public:
OrExpression(Expression* l, Expression* r) : left(l), right(r) {}
bool interpret(Context& context) override {
std::cout << "OR 연산" << std::endl;
return left->interpret(context) || right->interpret(context);
}
};
class NotExpression : public Expression {
private:
Expression* operand;
public:
NotExpression(Expression* op) : operand(op) {}
bool interpret(Context& context) override {
std::cout << "NOT 연산" << std::endl;
return !operand->interpret(context);
}
};
int main() {
// 논리식: (A && B) || !A
Expression* expression =
new OrExpression (
new AndExpression(new Variable("A"), new Variable("B")), // A && B
new NotExpression(new Variable("A") // !A
)
);
Context context;
bool result = expression->interpret(context);
std::cout << "Result: " << (result ? "True" : "False") << std::endl;
return 0;
}
논리 표현식을 추상 구문트리(Abstract Syntax Tree, AST)로 표현하고
이 트리를 해석하여 표현식을 계산할 수 있다.
이제는 새로운 연산자나 표현식에서 구조화된 방식으로 처리 가능하다.
🎈 인터프리터 패턴 장단점
+ 유연성: 새로운 문법/언어를 추가하거나 기존 문법 확장에 용이
+ 재사용성: 표현식 및 문법 구문의 구성 요소를 재사용 가능 (+ 다양한 조합)
- 성능저하: 실행 시간에 표현식을 해석하기 때문에 컴파일러와 달리
성능면에서 부하가 발생할 수 있다.
그래서 별도의 Parser 분석기를 이용하며 성능 저하를 줄여볼 수 있다.
- 복잡성: 여러 개의 표현식 or 복잡한 문법에서는 코드가 복잡해질 수 있다.
🎈 다른 디자인 패턴과 비교
• Composite
두 패턴은 계층 구조를 사용하며, 복합 객체를 다루는 것에서 유사하지만
인터프리터 패턴은 주로 언어 구문 해석 사용되는 것에 반해
컴포지트 패턴은 객체 구성을 트리 구조로 표현하고 복합 객체를 다루는 데 사용된다.
두 패턴은 상태와 상태 전이를 관리에 비슷한 느낌이 있지만
인터프리터 패턴은 특정 도메인 언어 또는 표현식을 해석 등 사용 목적에 차이가 있다.
상태 패턴 (State Pattern)
상태(State) 패턴이란? • 객체 내부 상태에 맞춰 스스로 행동을 변경하는 패턴 • 객체는 마치 자신의 클래스를 바꾸는 것처럼 보인다. • if-else와 같은 분기문으로 상태전이 하는 것을 해소한다.
zoosso.tistory.com
• 전략 (Strategy)
두 패턴은 행동을 캡슐화하고 동적으로 변경 가능한 공통점이 있다.
💻 [디자인패턴] 전략 패턴 (Strategy Pattern)
전략 패턴 (Strategy Pattern) 이란? 전략(Strategy)은 코드 내부에서 로직(Logic)을 처리하는 「알고리즘」 어떤 목적 달성을 위한 수행 방식이라고 생각하면 좋다. 영화관에서 이벤트 영화 예매 방식을
zoosso.tistory.com
'까망 동네 > 디자인 패턴' 카테고리의 다른 글
[디자인 패턴] 관찰자(Observer) 패턴 (4) | 2023.11.06 |
---|---|
[디자인패턴] 컴포지트 패턴 (Composite Pattern) (1) | 2023.11.05 |
[디자인패턴] 커맨드 패턴 (Command Pattern) (1) | 2023.11.03 |
[디자인패턴] 장식자 패턴 (Decorator) (2) | 2023.11.01 |
[디자인패턴] 프로토타입 (Prototype Pattern) (1) | 2023.10.31 |
댓글