设计模式26-解析器模式

news2024/9/21 14:41:03

设计模式26-解析器模式

  • 动机
  • 定义与结构
    • 定义
    • 结构
  • C++代码推导
    • 代码说明
  • 优缺点
  • 应用
  • 总结

动机

  • 在软件构建过程中,如果某一特定领域的问题比较复杂,类似结构会不断重复的出现。如果使用普通的编程方式来实现,将面临非常频繁的变化。

  • 在这种情况下,将特定领域的问题表达为某种语法规则下的句子。然后构建一个解释器来解释这样的句子。从而达到解决问题的目的。

  • 解析器模式(Interpreter Pattern)主要用于设计一个语言的解释器,该语言可能是简单的命令语言、表达式语言、或某种配置语言。动机源于这样一个需求:在某些应用程序中,可能会涉及到对特定领域语言(DSL)的解释或执行。为了避免重复编写这些语言的解释代码,并使代码易于扩展和维护,解析器模式提供了一种可行的解决方案。

  • 解析器模式通过为语言的每一个表达式(或符号)定义一个类来实现解释操作。这些类通过组合来构建复杂的表达式,并且这些表达式可以在运行时被解释和执行。使用解析器模式可以让你轻松地为新的表达式添加支持,而无需修改现有代码。

定义与结构

定义

解析器模式是一种行为设计模式,它定义了一个语言的语法表示,并实现一个解释器来处理该语言的句子。解析器模式将表达式解析为抽象语法树(AST),然后通过遍历语法树来执行或评估表达式。

结构

在这里插入图片描述

这张图片展示了解析器模式(Interpreter Pattern)的类结构。解析器模式是一种行为设计模式,它定义了一个表达式的接口,用来解释一个特定的上下文中的表达式。这种模式被用于构建解释器,这些解释器用于分析字符串、数学表达式或任何其他需要解释的语法。

以下是类图中各部分的详细解释:

  1. Context 类

    • Context 通常是解析过程中的上下文环境。它包含了所有与解释操作相关的全局信息。在图中的类结构中,Context 被错误地描述为 TerminalExpressionNonterminalExpression 的基类,这在标准的解析器模式实现中是不常见的。实际上,Context 应该是独立于表达式类型的,用于在解释过程中传递数据。
  2. Expression 接口

    • 虽然图中没有明确显示,但在解析器模式中,通常会有一个 Expression 接口(或抽象类),它定义了 Interpret(Context) 方法。这个方法用于对表达式进行解释,并根据当前上下文环境返回结果。TerminalExpressionNonterminalExpression 通常会实现这个接口。
  3. TerminalExpression 类

    • TerminalExpression 是实现了 Expression 接口的类之一,用于表示解析树中的叶子节点。这些节点是表达式的最基本单元,例如字面量值(如数字、字符串等),它们不包含其他表达式。TerminalExpression 类的 Interpret(Context) 方法将直接返回该表达式的结果,而不需要进一步解析。
  4. NonterminalExpression 类

    • NonterminalExpression 也是实现了 Expression 接口的类,但它代表了解析树中的非叶子节点。这些节点通常包含了一个或多个其他表达式(子节点),并定义了如何将这些子表达式的解释结果组合起来形成最终的结果。NonterminalExpressionInterpret(Context) 方法会递归地调用其子节点的 Interpret 方法,并根据需要处理这些结果。
  5. Client 类

    • Client 类是解析器模式的使用者,它构建了一个表达式树(由 TerminalExpressionNonterminalExpression 实例组成),并通过调用根节点的 Interpret(Context) 方法来启动解释过程。Client 类负责设置解析所需的初始上下文,并处理解释结果。

C++代码推导

以下是一个简单的解析器模式示例,它实现了一个基本的数学表达式解释器,该解释器支持加法和减法操作。

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

// 上下文类,包含变量的值
class Context {
public:
    void setVariable(const std::string& name, int value) {
        variables[name] = value;
    }

    int getVariable(const std::string& name) const {
        auto it = variables.find(name);
        if (it != variables.end()) {
            return it->second;
        }
        return 0; // 默认返回0
    }

private:
    std::map<std::string, int> variables;
};

// 抽象表达式类
class Expression {
public:
    virtual ~Expression() = default;
    virtual int interpret(const Context& context) const = 0;
};

// 终结符表达式类,用于表示变量
class VariableExpression : public Expression {
public:
    VariableExpression(const std::string& name) : name_(name) {}

    int interpret(const Context& context) const override {
        return context.getVariable(name_);
    }

private:
    std::string name_;
};

// 终结符表达式类,用于表示数字常量
class NumberExpression : public Expression {
public:
    NumberExpression(int value) : value_(value) {}

    int interpret(const Context& context) const override {
        return value_;
    }

private:
    int value_;
};

// 非终结符表达式类,用于表示加法
class AddExpression : public Expression {
public:
    AddExpression(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right)
        : left_(std::move(left)), right_(std::move(right)) {}

    int interpret(const Context& context) const override {
        return left_->interpret(context) + right_->interpret(context);
    }

private:
    std::unique_ptr<Expression> left_;
    std::unique_ptr<Expression> right_;
};

// 非终结符表达式类,用于表示减法
class SubtractExpression : public Expression {
public:
    SubtractExpression(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right)
        : left_(std::move(left)), right_(std::move(right)) {}

    int interpret(const Context& context) const override {
        return left_->interpret(context) - right_->interpret(context);
    }

private:
    std::unique_ptr<Expression> left_;
    std::unique_ptr<Expression> right_;
};

int main() {
    Context context;
    context.setVariable("x", 10);
    context.setVariable("y", 20);

    // 表达式 x + y - 5
    auto expression = std::make_unique<SubtractExpression>(
        std::make_unique<AddExpression>(
            std::make_unique<VariableExpression>("x"),
            std::make_unique<VariableExpression>("y")),
        std::make_unique<NumberExpression>(5)
    );

    std::cout << "Result: " << expression->interpret(context) << std::endl; // 输出 25

    return 0;
}

代码说明

  1. Context(上下文):存储变量及其对应的值,提供获取变量值的接口。
  2. Expression(抽象表达式):定义了一个interpret方法,用于解释或计算表达式的值。
  3. VariableExpression(终结符表达式):表示变量,根据上下文返回变量的值。
  4. NumberExpression(终结符表达式):表示数字常量,返回常量值。
  5. AddExpression(非终结符表达式):实现加法操作。
  6. SubtractExpression(非终结符表达式):实现减法操作。
  7. Client(客户端):在main函数中创建表达式树,解释并计算表达式的值。

优缺点

优点

  1. 易于扩展:可以通过添加新的表达式类来扩展语言的语法,添加新操作无需修改现有的表达式类。
  2. 灵活性高:可以动态构建和解释表达式,适合解释和执行简单的DSL(领域特定语言)。

缺点

  1. 性能问题:对于复杂的语法规则或庞大的表达式,构建和解释的开销较大。
  2. 难以维护:表达式类的数量可能非常庞大,导致系统复杂度增加,难以维护。
  3. 有限应用场景:通常适用于简单的语言解释,复杂的语法解析需要更强大的解析器(如语法分析器)。

应用

  1. 解释简单的命令语言或配置语言:例如用于解释配置文件中的规则或处理脚本语言。
  2. 数学表达式解析:用于解析和计算数学表达式。
  3. 编译器或解释器的部分实现:在编译器中,用于解释特定语言的子集或生成代码的中间步骤。

访问器模式适合处理那些相对简单、易于表达的语法和表达式的解释操作,它在特定领域语言、数学表达式求值、规则引擎等场景中具有较高的实用性。

总结

  • 解析器模式的应用场合是解析器模式应用中的难点。只有满足业务规则频繁变化,且类似结构会不断重复出现。并且容易抽象为语法规则的问题,才适合使用解析器模式。

  • 使用解气模式来表示文法规则,从而可以使用。面向对象的技巧来方便的扩展文法。

  • 解析器模式比较适合简单的文法表示,对于复杂的文法表示解析模式会产生比较大的类层次结构。需要求助语法分析生成器这样的标准工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2079716.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉树算法算法【二叉树的创建、插入、删除、查找】

一、原理 1.1、二叉排序树的插入 1.2、二叉树的删除 &#xff08;1&#xff09;删除度为0的节点&#xff0c;就是最后的叶子节点&#xff0c;直接删除就可以了. &#xff08;2&#xff09;删除度为1的节点&#xff0c;就是爷爷节点接收孙子节点。 &#xff08;3&#xff09;删…

什么软件可以约束员工摸鱼行为?「5款软件助力企业管控员工上班摸鱼!」

你的企业是否也在面临这些问题&#xff1a; 1.工作效率下降&#xff1a;频繁的分心会打断工作连贯性&#xff0c;降低任务完成的质量和速度。 2.团队协作受损&#xff1a;个别员工的低效可能导致整个团队进度滞后&#xff0c;影响项目按时交付。 3.资源浪费&#xff1a;非工…

Git —— 1、Windows下安装配置git

Git简介 Git 是一个免费的开源分布式版本控制系统&#xff0c;旨在处理从小型到 快速高效的超大型项目。 Git 易于学习&#xff0c;占用空间小&#xff0c;性能快如闪电。 它超越了 Subversion、CVS、Perforce 和 ClearCase 等 SCM 工具 具有 cheap local branching、 方便的暂…

【分布式架构幂等性总结】

文章目录 幂等性什么场景需要幂等设计&#xff1f;产生幂等性的原因解决重复操作&#xff0c;实现幂等性 幂等性 接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的&#xff0c;不会因为多次点击而产生了副作用。比如&#xff1a;公交车刷卡&#xff0…

.NET8 Web 利用BAT命令 一键部署 IIS - CI-CD基础

1. Windows Server 前置准备 1.1 IIS安装好 1.2 .NET8 Sdk 运行时 安装 官方下载地址&#xff1a;https://dotnet.microsoft.com/zh-cn/download/dotnet/8.0 1.3 创建一个.NET8 WebMvc项目 生成发布包 微软MVC这个项目模板直接创建&#xff0c;发布 2. 利用 BAT 来一键部署…

特效与样式(5)——Timetables的使用

第一次使用timetables做学校课表的开发&#xff0c;里面的门道东西挺多的&#xff0c;比我想的要复杂很多。包括我现在也只是实现了课表的初级效果。 主要是标题部分&#xff0c;数据部分&#xff0c;还有颜色控制部分。每个表格都需要一个控制颜色&#xff0c;每次写数据的时候…

hyperf注解,自定义注解

注解是 Hyperf 非常强大的一项功能&#xff0c;可以通过注解的形式减少很多的配置&#xff0c;以及实现很多非常方便的功能。 结构 建立注解 在app下建立Annotation注解文件夹 在Annotation下建立Jim.php注解 下面的的Annotation 和 Target是全局注解&#xff0c;所以不需…

Go学习笔记(一)语法

标准库文档&#xff1a;Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国 B站课程&#xff1a;8小时转职Golang工程师(如果你想低成本学习Go语言) 课程作者语雀&#xff08;首页有更多内容&#xff09;&#xff1a;8小时转职Golang工程师 语雀 代码仓…

C语言基础(二十)

链表是一种常见的数据结构&#xff0c;通常用来存储一系列元素&#xff0c;每个元素由一个节点来表示。在链表中&#xff0c;每个节点包含两部分&#xff1a;数据元素本身和指向下一个节点的指针。这种结构使得链表中的元素在内存中不是连续存储的&#xff0c;而是通过指针连接…

可拖拽表单设计器都有哪些突出特点?

为了提高效率、降低开发成本&#xff0c;利用低代码技术平台的优势特点可以实现这一目标。究竟什么是低代码技术平台&#xff1f;都有哪些值得夸耀的特点和优势&#xff1f;今天&#xff0c;我们就带着这些问题&#xff0c;一起来了解低代码技术平台、可拖拽表单设计器的多个优…

香港站群服务器优势

香港站群服务器因其独特的地理位置和网络连接优势&#xff0c;在SEO优化、网站群管理和网络营销等方面受到广泛关注。其优势主要体现在以下几个方面&#xff0c;rak小编为您整理发布。 地理位置优越 连接亚洲国际市场&#xff1a;香港作为亚太地区的重要经济中心&#xff0c;具…

华为2024年秋招-结构与材料工程师-结构方向-机试题(四套)(每套四十题)

华为2024年招聘-结构与材料工程师-结构方向-机试题&#xff08;四套&#xff09;&#xff08;每套四十题&#xff09; 岗位——结构与材料工程师 岗位意向——结构 真题题目分享&#xff0c;完整版带答案(有答案和解析&#xff0c;答案非官方&#xff0c;未仔细校正&#xff…

详细了解如何设计和实现一个SSO系统?

一、SSO系统有什么好处&#xff1f; 1、用户角度&#xff1a;一次登录多次使用&#xff0c;无需记录多套用户名和密码&#xff0c;省事省心。 2、系统管理员角度&#xff1a;管理员只需要维护好一个统一的账号中心就可以了&#xff0c;方便 3、新系统开发角度&#xff1a;新系统…

(二十六)STL vector容器(动态数组)

动态数组vector是标准模版库&#xff08;STL, Stardard Template Library&#xff09;中的模版&#xff0c;它有着节省空间和使用方便的优势&#xff0c;我们用一个形象的例子来说明&#xff1a; 开学了&#xff0c;有40个学生来报名&#xff0c;想要存储每个同学的姓名&#…

数字验证:一文弄懂UVM的factory机制

如果我们用SystemVerilog构建验证平台&#xff0c;构建好了之后&#xff0c;想改变平台中的某个组件&#xff0c;例如将driver改成driver_new&#xff0c;我们需要重新定义一下driver_new&#xff0c;当然也可以直接从driver继承。但是我们还需要在driver对象例化的地方将drive…

PHP同城派送多区域运营配送小程序源码

&#x1f69a;&#x1f4a8;「同城派送多区域运营小程序」——让每一份需求快速触达&#xff01;&#x1f308;&#x1f680; &#x1f525; 开篇燃爆&#xff1a;同城生活新风尚&#xff0c;一键速达不是梦&#xff01; Hey小伙伴们&#xff0c;你还在为找不到合适的同城服务…

WEB渗透Win提权篇-PowerUp

提权工具合集包&#xff08;免费分享&#xff09;&#xff1a; 夸克网盘分享 往期文章 WEB渗透Win提权篇-提权工具合集-CSDN博客 WEB渗透Win提权篇-RDP&Firewall-CSDN博客 WEB渗透Win提权篇-MSSQL-CSDN博客 WEB渗透Win提权篇-MYSQL-udf-CSDN博客 WEB渗透Win提权篇-Acc…

02-03:原理图与PCB交互以及快速模块化

1原理图与PCB交互 ①在PCB界面&#xff0c;点击工具, 勾选交叉选择模式 ②过滤器只选择元器件 2.按页快速模块化 配合F9快捷键

运放阻抗和噪声(同相放大器的输入/输出阻抗 + 电压跟随器阻抗 + 噪声 +信噪比)

2024-8-27&#xff0c;星期一&#xff0c;21:03&#xff0c;天气&#xff1a;阴雨&#xff0c;心情&#xff1a;晴。培训终于结束啦&#xff0c;开始轮岗了&#xff0c;看了两天PPT&#xff0c;加油加油&#xff0c;继续学习。 今天继续学习第六章运算放大器&#xff0c;主要学…

修改SpringBoot项目中MyBatis的mapper.xml文件的位置

由于MyBatis默认的mapper.xml的扫描位置是resource文件下&#xff0c;但是不可能整个项目的mapper.xml文件都放在resource下&#xff0c;如果文件较少还行&#xff0c;但是如果文件比较多&#xff0c;虽然有插件可以点击跳转&#xff0c;但是每次都这样也太麻烦了&#xff0c;所…