设计模式——解释器模式

解释器模式

定义

解释器模式(Interpreter Pattern)是一种按照规定语法进行解析的模式,现实项目中用得较少。
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

优缺点、应用场景

优点

解释器是一个简单语法分析工具,最显著的特点就是拓展性。例如:添加一个运算符号的语法解释只需要添加一个类

缺点

  1. 引起类的膨胀。每个语法都要产生一个类,语法规则复杂时,可能产生大量类文件
  2. 采用递归调用,调试不便。
  3. 效率问题。由于使用了大量的循环和递归,当表达式过长且复杂时,可能出现效率问题。

应用场景

  1. 重复发生的问题。例如:多个应用服务器每天会产生大量的日志,数据要素相同但日志格式不同,这种情况就可以使用解释器模式,
  2. 一个简单语法需要解释的场景。期望使用一种(例如:符号)形式描述复杂逻辑,且类间还要进行递归调用的场景,可以考虑使用。

流程

  1. 输入一个表达式,包含值的占位符(a、b、c等)与运算符号(+、-)
  2. 对表达式字符串遍历,根据值的占位符数量要求用户输入对应个数的值,此时要确保每个占位符只能使用一次,不会出现循环赋值的情况
  3. 将值的占位符作为key,对应输入的值作为value,封装到map中
  4. 进入解释器模式的程序,开始运算

代码模拟场景

输入一个计算公式,并根据参数个数与运算符号,输出结果。

解释器模式

UML图

在这里插入图片描述

表达式抽象、实现

/**
 * 表达式 抽象类
 */
public abstract class Expression {
	/**
	 * 解析公式和数值
	 *
	 * @param map key是公式中的参数,value是参数对应的值
	 * @return 结果
	 */
	public abstract int interpreter(Map<String, Integer> map);

}

/**
 * 变量解析器
 */
public class VarExpression extends Expression {
	private final String key;

	public VarExpression(String key) {
		this.key = key;
	}

	@Override
	public int interpreter(Map<String, Integer> map) {
		return map.get(key);
	}
}

/**
 * 抽象运算符号解析器
 */
public abstract class SymbolExpression extends Expression {
	protected Expression left;
	protected Expression right;

	/**
	 * 所有的解析公式都应只关心自己左右两个表达式的结果
	 *
	 * @param left  表达式左部
	 * @param right 表达式右部
	 */
	public SymbolExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}
}

/**
 * 加法解析器
 */
public class AddExpression extends SymbolExpression {
	/**
	 * 所有的解析公式都应只关心自己左右两个表达式的结果
	 *
	 * @param left  表达式左部
	 * @param right 表达式右部
	 */
	public AddExpression(Expression left, Expression right) {
		super(left, right);
	}

	@Override
	public int interpreter(Map<String, Integer> map) {
		return super.left.interpreter(map) + super.right.interpreter(map);
	}
}

/**
 * 减法解析器
 */
public class SubExpression extends SymbolExpression {
	/**
	 * 所有的解析公式都应只关心自己左右两个表达式的结果
	 *
	 * @param left  表达式左部
	 * @param right 表达式右部
	 */
	public SubExpression(Expression left, Expression right) {
		super(left, right);
	}

	@Override
	public int interpreter(Map<String, Integer> map) {
		return super.left.interpreter(map) - super.right.interpreter(map);
	}
}

解释器封装类

/**
 * 解释器的封装类
 * 将运算符和运算符两边的值进行组合,实现解释
 */
public class Calculator {
	private final Expression expression;

	public Calculator(String expStr) {
		Stack<Expression> stack = new Stack<>();
		char[] cs = expStr.toCharArray();
		Expression left;
		Expression right;
		for (int i = 0; i < cs.length; i++) {
			switch (cs[i]) {
				// 加法
				case '+' -> {
					left = stack.pop();
					right = new VarExpression(String.valueOf(cs[++i]));
					stack.push(new AddExpression(left, right));
				}
				// 减法
				case '-' -> {
					left = stack.pop();
					right = new VarExpression(String.valueOf(cs[++i]));
					stack.push(new SubExpression(left, right));
				}
				default -> stack.push(new VarExpression(String.valueOf(cs[i])));
			}
		}
		this.expression = stack.pop();
	}

	public int run(Map<String, Integer> map) {
		return this.expression.interpreter(map);
	}
}

入口类

/**
 * 解释器模式 入口类
 */
public class ExpressionMain {
	public static void main(String[] args) {
		String expStr = getExpStr();
		Map<String, Integer> map = getValue(expStr);
		Calculator calculator = new Calculator(expStr);
		System.out.println("运算结果为:" + expStr + "=" + calculator.run(map));
	}

	/**
	 * 获取表达式
	 *
	 * @return 控制台输入的表达式
	 */
	private static String getExpStr() {
		System.out.println("输入表达式:");
		try {
			return (new BufferedReader(new InputStreamReader(System.in))).readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * 获得值映射
	 */
	public static Map<String, Integer> getValue(String expStr) {
		Map<String, Integer> map = new HashMap<>();
		char[] cs = expStr.toCharArray();
		try {
			for (char c : cs) {
				// 如果是值的占位符
				if (c != '+' && c != '-') {
					// 解决重复参数的问题,确保值的占位符唯一
					if (!map.containsKey(String.valueOf(c))) {
						String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
						map.put(String.valueOf(c), Integer.valueOf(in));
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return map;
	}
}

结果

在这里插入图片描述

参考书籍

秦小波《设计模式之禅》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java 设计模式——观察者模式

目录 1.概述2.结构3.案例实现3.1.抽象观察者3.2.观察对象3.3.具体观察者3.4.具体观察对象3.5.测试 4.优缺点5.使用场景6.JDK 源码解析——Observable / Observer6.1.Observable 类6.2.Observer 接口6.3.案例 1.概述 观察者模式 (Observer Pattern) 是一种行为型设计模式&#…

HP惠普暗影精灵9笔记本原装出厂Win11系统预装专用OEM系统镜像

暗影9笔记本电脑原厂Windows11系统包 OMEN by HP 16.1英寸游戏本16-wf0000,16-wf0001,16-wf0003,16-wf0004,16-wf0006,16-wf0008,16-wf0009,16-wf0010,16-wf0011,16-wf0012,16-wf0028,16-wf0029,16-wf0007,16-wf0032,16-wf0036,16-wf0043 链接&#xff1a;https://pan.baidu.…

[SQL系列] 从头开始学PostgreSQL Union Null 别名 触发器

初级的操作就是CRUD&#xff0c;但是高级的操作也是CRUD&#xff0c;只是语句写的更加复杂&#xff0c;不再是select * from table&#xff1b;这样简单&#xff0c;这次咱们学一些稍微高级点的。下面是上一篇文章。 [SQL系列] 从头开始学PostgreSQL 约束连接_Edward.W的博客-…

划片机的作用将晶圆分割成独立的芯片

划片机是将晶圆分割成独立芯片的关键设备之一。在半导体制造过程中&#xff0c;晶圆划片机用于将整个晶圆切割成单个的芯片&#xff0c;这个过程被称为“晶圆分割”或“晶圆切割”。 晶圆划片机通常采用精密的机械传动系统、高精度的切割刀具和先进的控制系统&#xff0c;以确保…

【C++ 重要知识点总结】表达式

表达式 1 基础 组合运算 优先级结合律 类型转换 运算符重载 左值和右值 2 算数运算符 3 逻辑和关系运算法 短路求值 逻辑与&#xff0c;当第一个判定为否的时候&#xff0c;不再执行第二个判定&#xff0c;可以用来屏蔽第二步的计算&#xff0c;代替条件判断&#xff0…

rabbitmq延时队列自动解锁库存

一、库存服务自动解锁库存 使用了最终一致性来解决分布式事务 当order服务出现异常回滚&#xff0c;此时ware服务无法回滚&#xff0c;怎么办&#xff1f; 使用seata全局事务虽然能在order服务出现异常导致回滚时使其他服务的也能同时回滚&#xff0c;但在流量大的情况下是使用…

【SpringBoot】从零开始封装自己的starter并且引入到其他项目中使用

从零开始封装自己的starter并且引入到其他项目中使用 简介 本文将介绍如何从零开始封装自己的starter并且引入到其他项目中使用 为什么要自己封装starter&#xff1f; 这样可以对spring以及其他第三方提供的starter做二次封装或者封装一些自己需要的内容提供给其他项目使用&…

【milvus】向量数据库,用来做以图搜图+人脸识别的特征向量

1. 安装milvus ref:https://milvus.io/docs 第一次装东西&#xff0c;要把遇到的问题和成功经验都记录下来。 1.Download the YAML file wget https://github.com/milvus-io/milvus/releases/download/v2.2.11/milvus-standalone-docker-compose.yml -O docker-compose.yml看…

行为型模式 - 策略模式

概述 先看下面的图片&#xff0c;我们去旅游选择出行模式有很多种&#xff0c;可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。 作为一个程序猿&#xff0c;开发需要选择一款开发工具&#xff0c;当然可以进行代码开发的工具有很多&#xff0c;可以选择Idea进行开发&…

准备WebUI自动化测试面试?这30个问题你必须掌握(二)

本文共有11000字&#xff0c;包含了后十五个问题&#xff0c;如需要前十五个问题&#xff0c;可查看文末链接~ 16. 在WebUI自动化测试中&#xff0c;你如何处理验证码或图像识别的问题&#xff1f; 1. 人工识别&#xff1a;一种简单但费时费力的方法是使用人工手动识别验证码。…

libbpf-bootstrap 开发指南:概念与如何安装

目录 概念 如何安装& 使用 git 地址 使用git clone 下载代码 安装依赖环境 安装libbpf 编译example 概念 libbpf-bootstrap 是一个项目&#xff0c;旨在帮助开发者快速启动和开发使用 eBPF (Extended Berkeley Packet Filter) 和 libbpf 的程序。eBPF 是一种可以在…

如何用Three.js + Blender打造一个web 3D展览馆

作者&#xff1a;vivo 互联网前端团队- Wei Xing 运营活动新玩法层出不穷&#xff0c;web 3D炙手可热&#xff0c;本文将一步步带大家了解如何利用Three.js和Blender来打造一个沉浸式web 3D展览馆。 一、前言 3D展览馆是什么&#xff0c;先来预览下效果&#xff1a; 看起来像…

element-ui message消息提示组件 ①延长提示消息在页面停留时间②提示消息换行

以实现下面的效果为示例 完整代码&#xff1a; let msgList ["数据1被引用", "数据2被引用"];// 使用html的换行标签拼接信息&#xff0c;默认行距太小&#xff0c;此处用两个<br/><br/>let message 以下数据不能删除&#xff0c;原因是&…

为什么很多公司都开始使用Go语言了?

越来越多的互联网大厂开始使用Go语言了&#xff0c;譬如腾讯、美团、滴滴、百度、Google、bilibili... 还有最初使用Python的字节跳动&#xff0c;甚至已经全面拥向Go了。这么多国内外首屈一指的公司&#xff0c;都在开始使用它了&#xff0c;它到底有什么优势呢&#xff1f;这…

Redis进阶底层原理-主从复制

Redis的主从节点都会记录对方的信息&#xff0c;核心还包括ReplicationID 和 offset &#xff0c; ReplicationID &#xff1a; 主从节点实例的ID &#xff0c;redis内部就是通过这个id去识别主从节点。offset&#xff1a;数据同步偏移量&#xff0c;也就是从节点每次从主节点同…

硬中断、软中断详解

文章目录 什么是中断&#xff1f; 什么是计算机的中断&#xff1f; 什么叫硬中断、什么叫软中断&#xff1f; 怎么查看硬中断、软中断 查看硬中断的运行情况 cat /proc/interrupts 查看软中断的运行情况 cat /proc/softirqs 怎么排查软中断过高的问题&#xff1f; 软中断注意事…

noSQL的小练习

目录 Redis&#xff1a; 1、 string类型数据的命令操作&#xff1a; 2、 list类型数据的命令操作&#xff1a; 3、 hash类型数据的命令操作&#xff1a; MongoDB&#xff1a; 1. 创建一个数据库 名字grade 2. 数据库中创建一个集合名字 class 3. 集合中插入若…

接入端口与中继端口

交换机端口是支持 IT 的基本组件&#xff0c;可实现网络通信。这些有线硬件设备负责连接并允许在不同设备和连接到其端口的网络部分之间进行数据传输。由于网络管理员在确保网络连接和可用性方面发挥着关键作用&#xff0c;因此网络管理员必须清楚地了解、映射和查看其网络交换…

从小白到大神之路之学习运维第64天--------Zabbix监控mysql、ftp服务以及自定义配置

第三阶段基础 时 间&#xff1a;2023年7月19日 参加人&#xff1a;全班人员 内 容&#xff1a; Zabbix监控mysql、ftp服务以及自定义 目录 一、Zabbix监控mysql数据库 二、Zabbix监控ftp服务 三、Zabbix自定义监控项 整体zabbix搭建完成&#xff0c;server端huyang1监…

SpringBoot中整合Sharding Sphere实现数据加解密/数据脱敏/数据库密文,查询明文

场景 为防止数据泄露&#xff0c;需要在插入等操作时将某表的字段在数据库中加密存储&#xff0c;在需要查询使用时明文显示。 Sharding Sphere ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈&#xff0c; 它由Sharding-JDBC、Sharding-Proxy和Shardi…