当前位置: 首页 > news >正文

一次解释器模式的实际使用

先说我的需求

给定下面一个表达式字符串

0;1;[2,4);[4,6);[6,12);>=12

在给定一个数值,例如 5

要求,找出满足5 的表达式,例如5 应该输出 [4,6)

我先把数据拆分下,如上所示,每个表达式都用的分号;隔开

于是就拆分成了一个列表

0

1

[2,4)

开始实现功能,以下为第一次实现,没有使用解释器模式


import java.util.List;

/**
 * 范围区间值策略
 * 示例 <=25;(25,35];[35,45);[45,55);[55,60);[60,65);>=65
 * 强制!必须由小到大排序,必须是此格式,否则该接口无法正常工作
 *
 * @author SUN
 * @date 04/09/2022
 */
public class RangeValuePolicy implements ValuePolicy {

	private static final String LEFT_OPEN_RANGE_SYMBOL = "[";
	private static final String RIGHT_OPEN_RANGE_SYMBOL = "]";
	private static final String LEFT_CLOSE_RANGE_SYMBOL = "(";
	private static final String RIGHT_CLOSE_RANGE_SYMBOL = ")";
	private static final String EQUALS_SYMBOL = "=";

	private static final String LESS_THAN_SYMBOL = "<";
	private static final String GRANT_THAN_SYMBOL = ">";
	private static final String COMMA_SYMBOL = ",";


	@SuppressWarnings("all")
	@Override
	public String compute(Object value, List<String> compareValue) {
		long longValue;
		try {
			longValue = Long.parseLong(String.valueOf(value));
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("解析出错!参数不是数值类型:" + value);
		}

		for (String express : compareValue) {
			boolean startWithLt = express.startsWith(LESS_THAN_SYMBOL);
			boolean startWithGt = express.startsWith(GRANT_THAN_SYMBOL);

			if (startWithLt || startWithGt) {

				int equals = express.indexOf(EQUALS_SYMBOL);
				if (equals != -1) {
					// 存在
					// 获取小于等于的数字
					long expressValue = Long.parseLong(express.substring(2));

					if (startWithLt) {
						if (longValue <= expressValue) {
							return express;
						}
					} else {

						if (longValue >= expressValue) {
							return express;
						}
					}


				} else {
					// 获取小于的数字
					long expressValue = Long.parseLong(express.substring(1));

					if (startWithLt) {
						if (longValue < expressValue) {
							return express;
						}
					} else {
						if (longValue > expressValue) {
							return express;
						}
					}
				}
				continue;
			}

			// 区间范围判断
			String[] compareArray = express.split(COMMA_SYMBOL);

			if (compareArray.length == 2) {
				String left = compareArray[0];
				String right = compareArray[1];


				// 左区间符号
				String leftRangeSymbol = left.substring(0, 1);
				// 左区间数值
				long leftRangeValue = Long.parseLong(left.substring(1));

				// 右区间符号
				String rightRangeSymbol = right.substring(right.length() - 1);
				// 右区间数值
				long rightRangeValue = Long.parseLong(right.substring(0, right.length() - 1));

				// 判断是否满足条件
				if (
					// 值大于等于 开区间值
						(LEFT_OPEN_RANGE_SYMBOL.equals(leftRangeSymbol) && longValue >= leftRangeValue)
								// 或者 值大于闭区间值
								|| LEFT_CLOSE_RANGE_SYMBOL.equals(leftRangeSymbol) && longValue > leftRangeValue) {


					if (
						// 值小于等于 开区间值
							(RIGHT_OPEN_RANGE_SYMBOL.equals(rightRangeSymbol) && longValue <= rightRangeValue)

									// 或者值小于闭区间值
									|| RIGHT_CLOSE_RANGE_SYMBOL.equals(rightRangeSymbol) && longValue < rightRangeValue) {


						// 满足表达式
						return express;
					}
				}

			} else {

				// 单值判断
				Long expressLongValue = Long.valueOf(express);
				if (expressLongValue.equals(longValue)) {
					return express;
				}

				continue;
			}
		}
		return null;
	}
}

这段代码看起来... 很直观,简单,但是却不易维护,没有扩展性。

解释器模式刚好可以实现这个功能,学起来还是有点痛苦,以至于我第一次看时完全无法理解。不过好在,我找到一本书,叫做《秒懂设计模式》,终于理解了。

阅读链接 秒懂设计模式-刘韬-微信读书 (qq.com)

 学会了解释器模式,现在开始改造代码,首当其冲的难点在于如何定义表达式,如何定义终结表达式与非终结表达式。

好的,首先画一幅只有自己能够看懂的图,来帮助自己梳理逻辑

 

0;1;[2,4);[4,6);[6,12);>=12

对于给定表达式,一个个来看,首先第一种 0 和 1

这种的判断就是 == 直接等于,也就是等于

再看第二种 >= 这种是可以拆分的,也就是 大于 和 等于 两个条件

此时,结构变成了如此

 区间如何表示呢?[1,3)

其实可以发现,区间属于复合运算,就是左区间 和 右区间 的运算

将区间拆开 分为左区间 和 右区间 

即 [1    3)

 一个个分析,对于这半个区间,特点就是一个符号 + 一个数值

符号代表了判断的规则,数值代表比较的内容

对于[1 左闭合区间 可以拆分为 >1

对于(1 左闭合区间 可以拆分为 >=1

右闭合区间同理

而拆分后的结果又在上图的语法树上,证明是可以用的

由于区间是两个表达式,所以得新建一个表达式类型

区间(1,3)就如下结构表示

闭区间如下表示 (紫色粗线只为看起来醒目些,无其他意义)

 

结构可以了,看看代码最终实现吧

git地址 https://gitee.com/sixsixsix516/design-mode-interpreter

package com.example;

/**
 * 解释器接口
 * @author SUN
 * @date 2022/9/7
 */
public abstract class AbstractExpression {

	/**
	 * 当前表达式字符串
	 */
	protected String express;

	/**
	 * 待比较的值
	 */
	protected long compareValue;

	/**
	 * 解释方法
	 * @return true符合条件 false不符合条件
	 */
	public abstract boolean interpret(long value);

	/**
	 * 从表达式中解析出要比较的value
	 */
	protected long parseExpressCompareValue(String compareValueExpress) {
		return 0;
	}

}
package com.example.ultimate;


import com.example.AbstractExpression;

/**
 * 等于
 *
 * @author SUN
 * @date 2022/9/7
 */
public class EqualExpress extends AbstractExpression {

	public EqualExpress(long compareValue) {
		super.compareValue = compareValue;
	}

	@Override
	public boolean interpret(long value) {
		return super.compareValue == value;
	}

}
package com.example.ultimate;


import com.example.AbstractExpression;
import com.example.constant.ExpressConstant;

/**
 * 大于等于
 *
 * @author SUN
 * @date 2022/9/7
 */
public class GreaterThanEqualExpress extends AbstractExpression {


	/**
	 * 大于
	 */
	private final GreaterThanExpress greaterThanExpress;

	/**
	 * 等于
	 */
	private final EqualExpress equalExpress;


	public GreaterThanEqualExpress(String compareValueExpress) {
		super.express = compareValueExpress;

		long compareValue = parseExpressCompareValue(compareValueExpress);
		this.greaterThanExpress = new GreaterThanExpress(compareValue);
		this.equalExpress = new EqualExpress(compareValue);
	}

	public GreaterThanEqualExpress(long compareValue) {
		this.greaterThanExpress = new GreaterThanExpress(compareValue);
		this.equalExpress = new EqualExpress(compareValue);
	}


	@Override
	public boolean interpret(long value) {
		return greaterThanExpress.interpret(value) || equalExpress.interpret(value);
	}

	/**
	 * 解析格式 >=10
	 */
	@Override
	protected long parseExpressCompareValue(String compareValueExpress) {
		return Long.parseLong(compareValueExpress.substring(ExpressConstant.GRANT_THAN_EQUALS_SYMBOL.length()));
	}
}
package com.example;


import com.example.ultimate.*;

import java.util.ArrayList;
import java.util.List;

import static com.example.constant.ExpressConstant.*;

/**
 * @author SUN
 * @date 2022/9/7
 */
public class RangeValuePolicy {

	/**
	 * 表达式列表、语法树
	 */
	private List<AbstractExpression> abstractExpressionList;

	public String interpret(long value) {
		for (AbstractExpression abstractExpression : abstractExpressionList) {
			boolean interpret = abstractExpression.interpret(value);
			if (interpret) {
				return abstractExpression.express;
			}
		}
		return null;
	}

	/**
	 * 语法解析
	 *
	 * @param expressList <10; <=0;[2,4);[4,6);[6,12);>=12  以分号分隔的列表
	 */
	public void parse(List<String> expressList) {
		abstractExpressionList = new ArrayList<>();

		for (String express : expressList) {

			if (express.startsWith(LESS_THAN_EQUALS_SYMBOL)) {
				abstractExpressionList.add(new LessThanEqualExpress(express));

			} else if (express.startsWith(LESS_THAN_SYMBOL)) {
				abstractExpressionList.add(new LessThanExpress(express));

			} else if (express.startsWith(GRANT_THAN_EQUALS_SYMBOL)) {
				abstractExpressionList.add(new GreaterThanEqualExpress(express));

			} else if (express.startsWith(GRANT_THAN_SYMBOL)) {
				abstractExpressionList.add(new GreaterThanExpress(express));

			} else if (express.startsWith(LEFT_CLOSE_RANGE_SYMBOL) || express.startsWith(LEFT_OPEN_RANGE_SYMBOL)) {
				// 区间
				abstractExpressionList.add(parseRangeExpress(express));
			}
		}
	}

	/**
	 * 解析区间表达式
	 */
	private RangeExpress parseRangeExpress(String express) {
		String[] rangeArray = express.split(",");

		// 左区间表达式 格式 (1 或 [16
		String leftExpressSymbol = rangeArray[0];
		// 左区间符号 ( [
		String leftSymbol = leftExpressSymbol.substring(0, 1);
		// 左区间数值
		long leftValue = Long.parseLong(leftExpressSymbol.substring(1));

		AbstractExpression leftExpress;
		if (leftSymbol.equals(LEFT_OPEN_RANGE_SYMBOL)) {
			leftExpress = new GreaterThanExpress(leftValue);
		} else {
			leftExpress = new GreaterThanExpress(leftValue);
		}

		// 右区间表达式
		String rightExpressSymbol = rangeArray[1];
		// 右区间符号  ) ]
		String rightRangeSymbol = rightExpressSymbol.substring(rightExpressSymbol.length() - 1);
		// 右区间数值
		long rightRangeValue = Long.parseLong(rightExpressSymbol.substring(0, rightExpressSymbol.length() - 1));


		AbstractExpression rightExpress;
		if (rightRangeSymbol.equals(RIGHT_OPEN_RANGE_SYMBOL)) {
			rightExpress = new LessThanEqualExpress(rightRangeValue);
		} else {
			rightExpress = new LessThanExpress(rightRangeValue);
		}

		return new RangeExpress(leftExpress, rightExpress, express);
	}


}

代码就随便粘几个,完整的仓库下载后自己看

 git地址 https://gitee.com/sixsixsix516/design-mode-interpreter

相关文章:

  • C++入门·收尾
  • 25.CF992E Nastya and King-Shamans 转化+线段树二分
  • 快来带您了解中秋节的前世今生
  • 分布式锁之防止超卖 --mysql原子操作,乐观锁,redis事务,乐观锁
  • 【算法刷题】第一篇——哈希
  • 小脚本杂文shell脚本
  • 网络热的查询易语言代码
  • 医美健康这类在医疗行业的推广要怎么做?
  • uni-app开发,防止踩坑
  • mac M1 安装AndroidStudio打开真机调试
  • 备战数学建模40-遗传算法优化bp神经网络(攻坚站4)
  • 解决Java使用response下载文件报错,并总结可能出错的原因: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。
  • C# .Net AOP 演进历史POP OOP 代码细节篇
  • Pytorch学习——入门知识
  • LeetCode 刷题系列 -- 1254. 统计封闭岛屿的数目
  • 【comparator, comparable】小总结
  • canvas 高仿 Apple Watch 表盘
  • css系列之关于字体的事
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • Go 语言编译器的 //go: 详解
  • Java 最常见的 200+ 面试题:面试必备
  • js学习笔记
  • linux安装openssl、swoole等扩展的具体步骤
  • PhantomJS 安装
  • React-flux杂记
  • Redux系列x:源码分析
  • VUE es6技巧写法(持续更新中~~~)
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 工程优化暨babel升级小记
  • 缓存与缓冲
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 如何合理的规划jvm性能调优
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 译米田引理
  • 正则表达式小结
  • 智能合约Solidity教程-事件和日志(一)
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • ​Java并发新构件之Exchanger
  • ​第20课 在Android Native开发中加入新的C++类
  • #include<初见C语言之指针(5)>
  • $.each()与$(selector).each()
  • (13):Silverlight 2 数据与通信之WebRequest
  • (3)nginx 配置(nginx.conf)
  • (二)hibernate配置管理
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (论文阅读40-45)图像描述1
  • (三) diretfbrc详解
  • (转)大型网站架构演变和知识体系
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .bashrc在哪里,alias妙用
  • .NET gRPC 和RESTful简单对比
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NET 中让 Task 支持带超时的异步等待