《设计模式的艺术》笔记 - 解释器模式

介绍

        解释器模式定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。

实现

myclass.h

//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include 
#include 
#include 
#include 
#include 

class Context {

};

class AbstractExpression { // 抽象表达式
public:
    virtual float interpret() = 0;
};

class Add : public AbstractExpression {    // 非终结符表达式
public:
    Add(std::shared_ptr left, std::shared_ptr right);

    float interpret() override;

private:
    std::shared_ptr m_left;
    std::shared_ptr m_right;
};

class Substract : public AbstractExpression {    // 非终结符表达式
public:
    Substract(std::shared_ptr left, std::shared_ptr right);

    float interpret() override;

private:
    std::shared_ptr m_left;
    std::shared_ptr m_right;
};

class Multiply : public AbstractExpression {    // 非终结符表达式
public:
    Multiply(std::shared_ptr left, std::shared_ptr right);

    float interpret() override;

private:
    std::shared_ptr m_left;
    std::shared_ptr m_right;
};

class Division : public AbstractExpression {    // 非终结符表达式
public:
    Division(std::shared_ptr left, std::shared_ptr right);

    float interpret() override;

private:
    std::shared_ptr m_left;
    std::shared_ptr m_right;
};

class Negative : public AbstractExpression {    // 非终结符表达式
public:
    Negative(std::shared_ptr exp);

    float interpret() override;

private:
    std::shared_ptr m_exp;
};

class Value : public AbstractExpression {
public:
    Value(float val);

    float interpret() override;

private:
    float m_val;
};

class ExpressionParser {
public:
    ExpressionParser(const std::string &expStr);

    std::shared_ptr getExpression();

private:
    void popOperation();

    std::vector m_ops;
    std::vector> m_vals;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"
#include 
#include 

Add::Add(std::shared_ptr left, std::shared_ptr right) {
    m_left = left;
    m_right = right;
}

float Add::interpret() {
    return m_left->interpret() + m_right->interpret();
}

Substract::Substract(std::shared_ptr left, std::shared_ptr right) {
    m_left = left;
    m_right = right;
}

float Substract::interpret() {
    return m_left->interpret() - m_right->interpret();
}

Multiply::Multiply(std::shared_ptr left, std::shared_ptr right) {
    m_left = left;
    m_right = right;
}

float Multiply::interpret() {
    return m_left->interpret() * m_right->interpret();
}

Division::Division(std::shared_ptr left, std::shared_ptr right) {
    m_left = left;
    m_right = right;
}

float Division::interpret() {
    return m_left->interpret() / m_right->interpret();
}

Negative::Negative(std::shared_ptr exp) {
    m_exp = exp;
}

float Negative::interpret() {
    return -m_exp->interpret();
}

Value::Value(float val) {
    m_val = val;
}

float Value::interpret() {
    return m_val;
}

ExpressionParser::ExpressionParser(const std::string &expStr) {
    char prev = '\0', c, op;
    std::shared_ptr exp;
    std::unordered_map brackets = {{'}', '{'}, {']', '['}, {')', '('}};
    float val;

    for (int i = 0; i < expStr.length(); ++i) {
        c = expStr[i];
        if (c == ' ') {
            continue;
        } else if (c == '+') {
            while (m_ops.size() > 0 && m_ops[m_ops.size() - 1] != '{' && m_ops[m_ops.size() - 1] != '[' && m_ops[m_ops.size() - 1] != '(') {
                popOperation();
            }
            m_ops.push_back(c);
            prev = c;
        } else if (c == '-') {
            if (prev == '\0' || prev == '{' || prev == '[' || prev == '(') {
                m_vals.push_back(0);
            } else {
                while (m_ops.size() > 0 && m_ops[m_ops.size() - 1] != '{' && m_ops[m_ops.size() - 1] != '[' && m_ops[m_ops.size() - 1] != '(') {
                    popOperation();
                }
            }
            m_ops.push_back(c);
            prev = c;
        } else if (c == '*' || c == '/') {
            if (m_ops.size() > 0 && (m_ops[m_ops.size() - 1] == '*' || m_ops[m_ops.size() - 1] == '/')) {
                popOperation();
            }
            m_ops.push_back(c);
            prev = c;
        } else if (c == '{' || c == '[' || c == '(') {
            m_ops.push_back(c);
            prev = c;
        } else if (c == '}' || c == ']' || c == ')') {
            while (m_ops.size() > 0) {
                op = m_ops[m_ops.size() - 1];
                if (op == brackets[c]) {
                    m_ops.pop_back();
                    break;
                } else {
                    popOperation();
                }
            }
        } else if (c >= '0' && c <= '9'){
            char buf[128];
            int j = 0;
            while (c == '.' || (c >= '0' && c <= '9')) {
                buf[j] = c;
                j++;
                i++;
                c = expStr[i];
            }
            prev = '0';
            --i;
            buf[j] = '\0';
            val = atof(buf);
            exp.reset(new Value(val));
            m_vals.push_back(exp);
        }
    }

    if (m_ops.size() > 0) {
        popOperation();
    }
    if (m_vals.size() != 1) {
        goto failed;
    }
    return;

failed:
    m_vals.resize(1);
    m_vals[0] = nullptr;
}

void ExpressionParser::popOperation() {
    char op = m_ops[m_ops.size() - 1];
    std::shared_ptr exp;

    if (op == '+') {
        exp.reset(new Add(m_vals[m_vals.size() - 2], m_vals[m_vals.size() - 1]));
    } else if (op == '-') {
        exp.reset(new Substract(m_vals[m_vals.size() - 2], m_vals[m_vals.size() - 1]));
    } else if (op == '*') {
        exp.reset(new Multiply(m_vals[m_vals.size() - 2], m_vals[m_vals.size() - 1]));
    } else if (op == '/') {
        exp.reset(new Division(m_vals[m_vals.size() - 2], m_vals[m_vals.size() - 1]));
    } else {
        return;
    }
    m_ops.pop_back();
    m_vals.pop_back();
    m_vals.pop_back();
    m_vals.push_back(exp);
}

std::shared_ptr ExpressionParser::getExpression() {
    return m_vals[0];
}

main.cpp

#include 
#include 
#include "myclass.h"

int main() {
    ExpressionParser *expressionParser = new ExpressionParser("(1+2)*(6-2)/2+1");
    auto exp = expressionParser->getExpression();
    if (exp) {
        std::cout << exp->interpret() << std::endl;
    } else {
        std::cout << 0 << std::endl;
    }

    return 0;
}

总结

优点

        1. 易于改变和扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。

        2. 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。

        3. 实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。

        4. 增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合开闭原则。

缺点

        1. 对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一种语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。

        2. 执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

适用场景

        1. 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。

        2. 一些重复出现的问题可以用一种简单的语言来进行表达。

        3. 一个语言的文法较为简单。

        4. 执行效率不是关键问题。(注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。)

练习

myclass.h

//
// Created by yuwp on 2024/1/12.
//

#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H

#include 
#include 
#include 
#include 
#include 

/**
 * COPY VIEW FROM srcDB TO desDB 表示将数据库srcDB中的所有视图对象都复制至数据库desDB
 * MOVE TABLE Student FROM srcDB TO desDB 表示将数据库srcDB中的Student表移动至数据库desDB
 * expression ::= operation object FROM string to string
 * operation ::= 'COPY' | 'MOVE'
 * object ::= 'VIEW' | 'TABLE string'
 */

class AbstractNode {
public:
    virtual std::string interpret() = 0;
};

class SentenceNode : public AbstractNode {  // expression 简单句子,非终结符表达式
public:
    SentenceNode(std::shared_ptr operation, std::shared_ptr object, std::string &srcDB, std::string &desDB);

    std::string interpret() override;

private:
    std::shared_ptr m_operation;
    std::shared_ptr m_object;
    std::string m_srcDB;
    std::string m_desDB;
};

class OperationNode : public AbstractNode { // 终结符表达式
public:
    OperationNode(std::string operation);
    std::string interpret() override;
private:
    std::string m_operation;
};

class ObjectNode : public AbstractNode {    // 终结符表达式
public:
    ObjectNode(std::string object, std::string name = "");

    std::string interpret() override;

private:
    std::string m_object;
    std::string m_name;
};

class InstructionHandler {
public:
    void handle(std::string &instruction);

    std::string output();

private:
    std::shared_ptr m_node;
};

#endif //DESIGNPATTERNS_MYCLASS_H

myclass.cpp

//
// Created by yuwp on 2024/1/12.
//

#include "myclass.h"
#include 
#include 
#include 


SentenceNode::SentenceNode(std::shared_ptr operation, std::shared_ptr object,
                           std::string &srcDB, std::string &desDB) {
    m_operation = operation;
    m_object = object;
    m_srcDB = srcDB;
    m_desDB = desDB;
}

std::string SentenceNode::interpret() {
    return "将" + m_srcDB + "的" + m_object->interpret() + m_operation->interpret() + "到" + m_desDB;
}

OperationNode::OperationNode(std::string operation) {
    m_operation = operation;
}

std::string OperationNode::interpret() {
    if (m_operation == "COPY") {
        return "拷贝";
    } else if (m_operation == "MOVE") {
        return "移动";
    } else {
        return "无效指令";
    }
}

ObjectNode::ObjectNode(std::string object, std::string name) {
    m_object = object;
    m_name = name;
}

std::string ObjectNode::interpret() {
    if (m_object == "VIEW") {
        return "视图";
    } else if (m_object == "TABLE") {
        return m_name + "表";
    } else {
        return "无效指令";
    }
}

void InstructionHandler::handle(std::string &instruction) {
    std::istringstream iss(instruction);
    std::string token, token2, srcDB, desDB;
    std::shared_ptr op, obj;
    int i = 0;
    while (iss >> token) {
        if (token == "TO") {
            continue;
        } else if (token == "FROM") {
            if (i == 1) {
                obj.reset(new ObjectNode(token2, ""));
                ++i;
            }
            continue;
        }
        if (i == 0) {
            op.reset(new OperationNode(token));
            ++i;
        } else if (i == 1) {
            if (token2.length() <= 0) {
                token2 = token;
                continue;
            } else {
                obj.reset(new ObjectNode(token2, token));
                ++i;
            }
        } else if (i == 2){
            srcDB = token;
            ++i;
        } else if (i == 3) {
            desDB = token;
            ++i;
        }
    }
    m_node.reset(new SentenceNode(op, obj, srcDB, desDB));
}

std::string InstructionHandler::output() {
    return m_node->interpret();
}

main.cpp

#include 
#include 
#include "myclass.h"

int main() {
    InstructionHandler *instructionHandler = new InstructionHandler();
    std::string ins = "COPY VIEW FROM AA_DB TO BB_DB";
    instructionHandler->handle(ins);
    std::cout << instructionHandler->output() << std::endl;

    ins = "COPY TABLE student FROM AA_DB TO BB_DB";
    instructionHandler->handle(ins);
    std::cout << instructionHandler->output() << std::endl;

    delete instructionHandler;
    return 0;
}

你可能感兴趣的:(设计模式,设计模式,笔记,解释器模式)