解释器模式_行为型_GOF23

news2025/4/2 0:15:44

解释器模式

解释器模式(Interpreter Pattern)是一种行为型设计模式,核心思想是定义语言的文法规则,并构建一个解释器来解析和执行该语言中的表达式。它类似于“翻译器”——将符合特定语法规则的文本(如数学公式、脚本指令)转换为可执行的逻辑或计算结果,而无需直接硬编码解析逻辑。


一、通俗理解

假设你开发一个计算器程序:

  1. 传统方式:直接解析 "3+4*2" 字符串,需处理运算符优先级、括号嵌套等复杂逻辑,代码臃肿且难以扩展。
  2. 解释器模式
    • 表达式类(如 AddMultiply)表示文法规则,每个类封装一个操作。
    • 解释器将表达式字符串解析为树形结构(如 3 + (4 * 2)),递归调用各节点计算最终结果。
      这样新增运算符(如指数运算)只需添加新表达式类,无需修改核心逻辑。

二、模式结构

解释器模式包含以下角色:

  1. 抽象表达式(Expression):定义 interpret() 接口,声明解释操作。
  2. 终结符表达式(TerminalExpression):处理语法中的基础元素(如数字、变量)。
  3. 非终结符表达式(NonTerminalExpression):处理组合结构(如运算符、逻辑语句),通常包含其他表达式对象。
  4. 上下文(Context):存储解释过程中需要的全局信息(如变量值)。
  5. 客户端(Client):构建表达式树并触发解释过程。

三、适用场景
  1. 数学表达式求值:如计算器、公式引擎。
  2. 领域特定语言(DSL):如游戏脚本、配置文件解析。
  3. 规则引擎:如业务规则判断(如 "年龄>18 && 信用分>60")。
  4. 简单语法解析:如正则表达式、SQL条件子句。

不适用场景

  • 语法过于复杂(如完整编程语言),此时需专业解析工具(如ANTLR)。
  • 对性能要求极高,因递归解释可能导致效率问题。

四、代码实现
1. C++ 示例(数学表达式求值)
#include <iostream>  
#include <map>  
#include <string>  

// 抽象表达式  
class Expression {  
public:  
    virtual int interpret(const std::map<std::string, int>& context) = 0;  
    virtual ~Expression() = default;  
};  

// 终结符表达式:数字  
class Number : public Expression {  
    int value;  
public:  
    Number(int v) : value(v) {}  
    int interpret(const std::map<std::string, int>&) override { return value; }  
};  

// 非终结符表达式:加法  
class Add : public Expression {  
    Expression* left;  
    Expression* right;  
public:  
    Add(Expression* l, Expression* r) : left(l), right(r) {}  
    int interpret(const std::map<std::string, int>& ctx) override {  
        return left->interpret(ctx) + right->interpret(ctx);  
    }  
    ~Add() { delete left; delete right; }  
};  

// 客户端  
int main() {  
    // 表达式:2 + (3 + 5)  
    Expression* expr = new Add(new Number(2), new Add(new Number(3), new Number(5)));  
    std::map<std::string, int> context;  // 本例未使用变量  
    std::cout << "结果: " << expr->interpret(context);  // 输出:10  
    delete expr;  
    return 0;  
}  

解析

  • Add 组合左右表达式,递归计算值。
  • 扩展减法只需新增 Subtract 类。

2. Python 示例(逻辑条件判断)
from abc import ABC, abstractmethod  

class Expression(ABC):  
    @abstractmethod  
    def interpret(self, context):  
        pass  

# 终结符:变量值  
class Variable(Expression):  
    def __init__(self, name):  
        self.name = name  
    def interpret(self, context):  
        return context.get(self.name, False)  

# 非终结符:逻辑或  
class Or(Expression):  
    def __init__(self, expr1, expr2):  
        self.expr1 = expr1  
        self.expr2 = expr2  
    def interpret(self, context):  
        return self.expr1.interpret(context) or self.expr2.interpret(context)  

# 客户端  
context = {"A": True, "B": False}  
expr = Or(Variable("A"), Variable("B"))  
print(expr.interpret(context))  # 输出:True  

特点

  • 支持动态条件组合(如 A || (C && D))。

3. Java 示例(四则运算解析器)
import java.util.Stack;  

// 抽象表达式  
interface Expression {  
    int interpret();  
}  

// 终结符:数字  
class Number implements Expression {  
    private int value;  
    public Number(int v) { this.value = v; }  
    public int interpret() { return value; }  
}  

// 非终结符:加法  
class Add implements Expression {  
    private Expression left, right;  
    public Add(Expression l, Expression r) {  
        this.left = l;  
        this.right = r;  
    }  
    public int interpret() {  
        return left.interpret() + right.interpret();  
    }  
}  

// 客户端构建表达式树  
public class Client {  
    public static void main(String[] args) {  
        // 表达式: (5 + 3) - (2 * 4)  
        Expression expr = new Subtract(  
            new Add(new Number(5), new Number(3)),  
            new Multiply(new Number(2), new Number(4))  
        );  
        System.out.println("结果: " + expr.interpret());  // 输出:8 - 8 = 0  
    }  
}  

扩展性

  • 新增 MultiplyDivide 类即可支持更多运算符。

五、优缺点分析
优点缺点
1. 灵活扩展语法:新增规则只需添加类1. 类膨胀:每个语法规则对应一个类
2. 解耦解析与执行:逻辑清晰易维护2. 性能瓶颈:递归解释效率较低
3. 支持复杂表达式:树形结构处理嵌套逻辑3. 不适合复杂文法:需专业解析工具

六、总结

解释器模式通过语法树将文本指令转化为可执行逻辑,其核心价值在于:

  1. 抽象与封装:分离语法定义与解析逻辑,提升代码可读性。
  2. 领域适应性:为特定场景(如规则引擎、公式计算)提供轻量级解析方案。
  3. 实际应用:Spring表达式语言(SpEL)、正则表达式引擎均基于此模式。

扩展思考

  • 结合组合模式构建复杂语法树。
  • 使用预编译或缓存优化解释性能。

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

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

相关文章

YOLOv8+ Deepsort+Pyqt5车速检测系统

该系统通过YOLOv8进行高效的目标检测与分割&#xff0c;结合DeepSORT算法完成目标的实时跟踪&#xff0c;并利用GPU加速技术提升处理速度。系统支持模块化设计&#xff0c;可导入其他权重文件以适应不同场景需求&#xff0c;同时提供自定义配置选项&#xff0c;如显示标签和保存…

【干货】前端实现文件保存总结

⚠️⚠️文前推荐一下&#x1f449; 前端必备工具推荐网站(图床、API和ChatAI、智能AI简历、AI思维导图神器等实用工具): 站点入口&#xff1a;http://luckycola.com.cn/ 前端实现文件保存实现总结 在Web开发中&#xff0c;文件下载是常见的交互需求。本文将系统总结前端实现文…

并发编程之FutureTask.get()阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方案

FutureTask.get方法阻塞陷阱&#xff1a;深度解析线程池CPU飚高问题排查与解决方法 FutureTask.get()方法阻塞陷阱&#xff1a;深度解析线程池CPU飚高问题排查与解决方法1、情景复现1.1 线程池工作原理1.2 业务场景模拟1.3 运行结果1.4 发现问题&#xff1a;线程池没有被关闭1.…

在Ubuntu中固定USB设备的串口号

获取设备信息 lsusb # 记录设备的Vendor ID和Product ID&#xff08;例如&#xff1a;ID 0403:6001&#xff09;# 获取详细属性&#xff08;替换X和Y为实际设备号&#xff09; udevadm info -a /dev/ttyUSBX 结果一般如下 创建udev规则文件 sudo gedit /etc/udev/rules.d/us…

javaSE————文件IO(2)、

文件内容的读写——数据流 我们对于文件操作使用流对象Stream来操作&#xff0c;什么是流对象呢&#xff0c;水流是什么样的&#xff0c;想象一下&#xff0c;水流的流量是多种的&#xff0c;可以流100ml&#xff0c;也可以流1ml&#xff0c;流对象就和水流很像&#xff0c;我…

前端常问的宏观“大”问题详解(二)

JS与TS选型 一、为什么选择 TypeScript 而不是 JavaScript&#xff1f; 1. 静态类型系统&#xff1a;核心优势 TypeScript 的静态类型检查能在 编译阶段 捕获类型错误&#xff08;如变量类型不匹配、未定义属性等&#xff09;&#xff0c;显著减少运行时错误风险。例如&…

智慧电力:点亮未来能源世界的钥匙

在科技日新月异的今天&#xff0c;电力行业正经历着前所未有的变革。智慧电力&#xff0c;作为这一变革的核心驱动力&#xff0c;正逐步改变着我们对电力的认知和使用方式。它不仅是电力行业的一次技术革新&#xff0c;更是推动社会可持续发展、实现能源高效利用的重要途径。 智…

架构师面试(二十三):负载均衡

问题 今天我们聊微服务相关的话题。 大中型微服务系统中&#xff0c;【负载均衡】是一个非常核心的组件&#xff1b;在微服务系统的不同位置对【负载均衡】进行了实现&#xff0c;下面说法正确的有哪几项&#xff1f; A. LVS 的负载均衡一般通过前置 F5 或是通过 VIP keepa…

NSSCTF(MISC)—[justCTF 2020]pdf

相应的做题地址&#xff1a;https://www.nssctf.cn/problem/920 binwalk分离 解压文件2AE59A.zip mutool 得到一张图片 B5F31内容 B5FFD内容 转换成图片 justCTF{BytesAreNotRealWakeUpSheeple}

坚持“大客户战略”,昂瑞微深耕全球射频市场

北京昂瑞微电子技术股份有限公司&#xff08;简称“昂瑞微”&#xff09;是一家聚焦射频与模拟芯片设计的高新技术企业。随着5G时代的全面到来&#xff0c;智能手机、智能汽车等终端设备对射频前端器件在通信频率、多频段支持、信道带宽及载波聚合等方面提出了更高需求&#xf…

LiteDB 数据库优缺点分析与C#代码示例

LiteDB 是一个轻量级的 .NET NoSQL 嵌入式数据库,完全用 C# 开发,支持跨平台(Windows、Linux、MacOS),并提供类似于 MongoDB 的简单 API。它以单文件形式存储数据,类似于 SQLite,支持事务和 ACID 特性,确保数据的一致性和可靠性。 优缺点分析 优点: 轻量级与嵌入式:…

Linux系统中快速安装docker

1 查看是否安装docker 要检查Ubuntu是否安装了Docker&#xff0c;可以使用以下几种方法&#xff1a; 方法1&#xff1a;使用 docker --version 命令 docker --version如果Docker已安装&#xff0c;输出会显示Docker的版本信息&#xff0c;例如&#xff1a; Docker version …

CP15 协处理器

ARMv7-A 一共支持 16 个协处理器&#xff0c;编号从 CP0~CP15。这里仅对CP15进行描述。 1、ARMv7-A 协处理器 ARMv7-A 处理器除了标准的 R0~R15&#xff0c;CPSR&#xff0c;SPSR 以外&#xff0c;由于引入了 MMU、TLB、Cache 等内容&#xff0c;ARMv7-A 使用协处理器来对这些…

网络运维学习笔记(DeepSeek优化版)026 OSPF vlink(Virtual Link,虚链路)配置详解

文章目录 OSPF vlink&#xff08;Virtual Link&#xff0c;虚链路)配置详解1. 虚链路核心特性2. 基础配置命令3. 状态验证命令3.1 查看虚链路状态3.2 验证LSDB更新 4. 关键技术要点4.1 路径选择机制4.2 虚链路的链路优化 5. 环路风险案例 OSPF vlink&#xff08;Virtual Link&a…

【区块链安全 | 第十六篇】类型之值类型(三)

文章目录 函数类型声明语法转换成员合约更新时的值稳定性示例 函数类型 函数类型是函数的类型。函数类型的变量可以通过函数进行赋值&#xff0c;函数类型的参数可以用来传递函数并返回函数。 函数类型有两种类型&#xff1a;内部函数和外部函数。 内部函数只能在当前合约内调…

Kubernetes对象基础操作

基础操作 文章目录 基础操作一、创建Kubernetes对象1.使用指令式命令创建Deployment2.使用指令式对象配置创建Deployment3.使用声明式对象配置创建Deployment 二、操作对象的标签1.为对象添加标签2.修改对象的标签3.删除对象标签4.操作具有指定标签的对象 三、操作名称空间四、…

Java与代码审计-Java基础语法

Java基础语法 package com.woniuxy.basic;public class HelloWorld {//入口函数public static void main(String[] args){System.out.println("Hello World");for(int i0;i< args.length;i){System.out.println(args[i]);}} }运行结果如下: 但是下面那个没有参数…

Xenium | 细胞邻域(Cellular Neighborhood)分析(fixed radius)

上节我们介绍了空间转录组数据分析中常见的细胞邻域分析&#xff0c;CN计算过程中定义是否为细胞邻居的方法有两种&#xff0c;一种是上节我们使用固定K最近邻方法(fixed k-nearest neighbors)定义细胞Neighborhood&#xff0c;今天我们介绍另外一种固定半径范围内(fixed radiu…

Python:爬虫概念与分类

网络请求&#xff1a; https://www.baidu.com url——统一资源定位符 请求过程&#xff1a; 客户端&#xff0c;指web浏览器向服务器发送请求 请求&#xff1a;请求网址(request url)&#xff1b;请求方法(request methods)&#xff1b;请求头(request header)&…

SQLMesh调度系统深度解析:内置调度与Airflow集成实践

本文系统解析SQLMesh的两种核心调度方案&#xff1a;内置调度器与Apache Airflow集成。通过对比两者的适用场景、架构设计和操作流程&#xff0c;为企业构建可靠的数据分析流水线提供技术参考。重点内容包括&#xff1a; 内置调度器的轻量级部署与性能优化策略Airflow集成的端到…