iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0
Software Development

深入淺出設計模式 - 使用 C++系列 第 24

[Day 24] 以類別來表達文法規則 -解譯器模式 (Interpreter Pattern)

  • 分享至 

  • xImage
  •  

Intent

  • 解譯器模式是一種行為設計模式,主要用於解釋語言的語法和語義。它為解釋語言提供了一個形式化的機制,並且通過建立一個解釋器來解釋語言中的句子
  • https://ithelp.ithome.com.tw/upload/images/20231005/20138643aclQ04tEiD.png

[補充]: Formal Mechanism

  • 在解譯器模式中,"形式化" 主要指的是一套明確、結構化的規則和方法,用於解釋和執行特定語言或表達式的語法和語義
  • 這些規則和方法通常會被編碼為一個或多個 classes 和 methods,並且會遵循一定的設計原則和模式

主要組成

  • 語法規則 (Syntax Rules): 這些規則定義了語言的結構,通常會使用一種形式語法來表示 (例: BNF, ABNF, PEG, Regular Expression...等)
  • 語義規則 (Semantic Rules): 這些規則定義了語言元素的意義,通常會在解譯器的實現中明確指定。
  • 解釋引擎 (Interpretation Engine): 這是解譯器模式的核心部分,負責根據語法和語義規則來解釋和執行語言

Motivation

  • 當您需要實現一個簡單的語言或者需要解釋一個複雜的數據結構時,解譯器模式就會派上用場
  • 例如,SQL 查詢、正則表達式或者是一些簡單的程式語言

Applicability

  • 簡單語言解釋: 用於解釋一些簡單的語言或語法
  • 配置文件解析: 用於解析配置文件中的設置
  • 數學表達式計算: 用於解釋和計算數學表達式

Structure

https://ithelp.ithome.com.tw/upload/images/20231005/20138643PGrkqn7OY5.png

  • AbstractExpression (抽象表達式 / Expression): 定義了一個 interpret() 操作,所有在抽象語法樹(AST) 中的節點 (終端和非終端) 都會覆寫這個操作
  • TerminalExpression (終端表達式 / NumberExpression): 實現了 interpret() 操作,專門用於終端表達式
  • NonTerminalExpression (非終端表達式 / AdditionExpression, SubtractionExpression...等): 實現了 interpret() 操作,用於所有非終端表達式
  • Context (上下文 / String): 包含對解釋器全局的信息。這是一個需要被解釋和解析的字符串表達式
  • Client (客戶端 / ExpressionParser): 建立由 TerminalExpression 和 NonTerminalExpression 組成的抽象語法樹 (AST)。客戶端調用 interpret() 操作

Participants

  • Client (客戶端): 建立語法樹,並從中獲取解釋結果
  • Context (上下文): 這個類包含解譯器需要的所有全局信息,如變數的值等

Collaborations

  • Client 與 Context
    • Client 使用 Context 來初始化解釋器
  • AbstractExpression 與 Terminal/NonTerminal Expression
    • AbstractExpression 定義了解釋操作的接口,而 TerminalExpression 和 NonTerminalExpression 則實現了這些接口

Consequences

優點

  • 高度靈活 (High Flexibility):
    • 解釋器模式允許簡單地添加或修改解釋規則,這使得它非常適合於需要頻繁更新或擴展的語言或表達式解釋場景
    • 例如: 在配置管理或自定義查詢語言中,新的規則或命令可以輕易地被加入

缺點

  • 效能問題 (Performance Issues):
    • 由於解釋器模式通常涉及多次遍歷語法樹或其他數據結構,這可能會導致效能下降,特別是在處理大型或複雜的數據時
    • 優化策略: 使用快取 (Cache) 來優化頻繁計算的表達式

Implementation

#include <iostream>
#include <string>
#include <map>

// AbstractExpression
class AbstractExpression {
public:
    virtual int interpret(std::map<std::string, int>& variables) = 0;
    virtual ~AbstractExpression() {}
};

// TerminalExpression
class TerminalExpression : public AbstractExpression {
    std::string variable;
public:
    TerminalExpression(const std::string& var) : variable(var) {}
    int interpret(std::map<std::string, int>& variables) override {
        return variables[variable];
    }
};

// NonTerminalExpression
class AddExpression : public AbstractExpression {
    AbstractExpression* left;
    AbstractExpression* right;
public:
    AddExpression(AbstractExpression* l, AbstractExpression* r) : left(l), right(r) {}
    int interpret(std::map<std::string, int>& variables) override {
        return left->interpret(variables) + right->interpret(variables);
    }
    ~AddExpression() {
        delete left;
        delete right;
    }
};

int main() {
    // Context
    std::map<std::string, int> context;
    context["x"] = 5;
    context["y"] = 10;

    // Client
    AbstractExpression* expression = new AddExpression(new TerminalExpression("x"), new TerminalExpression("y"));
    std::cout << "Result: " << expression->interpret(context) << std::endl;

    delete expression;
    return 0;
}

Known Uses

  • Python 的 ast 模塊:用於解釋 Python 程式碼
  • Java 的 Pattern 類:用於解釋正則表達式

Reference

  1. http://corrupt003-design-pattern.blogspot.com/2017/01/interpreter-pattern.html
  2. https://www.runoob.com/design-pattern/interpreter-pattern.html
  3. https://www.geeksforgeeks.org/interpreter-design-pattern/
  4. https://springframework.guru/gang-of-four-design-patterns/interpreter-pattern/

上一篇
[Day 23] 集中管理大量物件實例 - 蠅量模式 (Flyweight Pattern)
下一篇
[Day 25] 集中對象間複雜的控制和溝通 — 中介者模式 (Mediator Pattern)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言