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

0133_解释器模式(Interpreter)

解释器模式(Interpreter)

意图

给定一种语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

UML 图

Interpreter

优点

  1. 易于扩展文法:由于使用类来表示语言的文法规则,可以通过继承来扩展文法
  2. 易于实现文法:实现文法中的每个规则都很简单,可以方便地改变和扩展文法
  3. 增加新的解释表达式方便:增加新的解释表达式不需要修改现有表达式
  4. 可组合性:可以通过组合多个表达式来构建复杂的解释器

缺点

  1. 复杂文法难以维护:对于复杂的文法,解释器模式会定义过多的类,导致系统变得复杂
  2. 执行效率较低:由于通常使用递归调用,解释器的执行效率可能较低
  3. 应用场景有限:适用于简单的文法,复杂文法需要使用其他技术如编译器或解析器生成器
  4. 难以扩展复杂操作:添加新的操作需要修改所有表达式类

代码示例

以机器人指令解释系统为例:

1. 抽象表达式接口 (Abstract Expression)

// 抽象表达式接口
public interface RobotExpression {int interpret(RobotContext context);String getDescription();
}

2. 终结符表达式 (Terminal Expressions)

// 移动指令
public class MoveExpression implements RobotExpression {private int distance;public MoveExpression(int distance) {this.distance = distance;}@Overridepublic int interpret(RobotContext context) {context.addToLog("移动 " + distance + " 米");return distance;}@Overridepublic String getDescription() {return "移动 " + distance + " 米";}
}// 转向指令
public class TurnExpression implements RobotExpression {private String direction;public TurnExpression(String direction) {this.direction = direction;}@Overridepublic int interpret(RobotContext context) {context.addToLog("转向 " + direction);return 0; // 转向不消耗能量}@Overridepublic String getDescription() {return "转向 " + direction;}
}// 抓取指令
public class GrabExpression implements RobotExpression {private String object;public GrabExpression(String object) {this.object = object;}@Overridepublic int interpret(RobotContext context) {context.addToLog("抓取 " + object);return 5; // 抓取消耗5单位能量}@Overridepublic String getDescription() {return "抓取 " + object;}
}

3. 非终结符表达式 (Nonterminal Expressions)

// 重复指令
public class RepeatExpression implements RobotExpression {private int times;private RobotExpression expression;public RepeatExpression(int times, RobotExpression expression) {this.times = times;this.expression = expression;}@Overridepublic int interpret(RobotContext context) {int totalEnergy = 0;context.addToLog("开始重复 " + times + " 次");for (int i = 0; i < times; i++) {context.addToLog("第 " + (i+1) + " 次执行:");totalEnergy += expression.interpret(context);}context.addToLog("重复执行完成");return totalEnergy;}@Overridepublic String getDescription() {return "重复 " + times + " 次: " + expression.getDescription();}
}// 序列指令
public class SequenceExpression implements RobotExpression {private List<RobotExpression> expressions = new ArrayList<>();public void addExpression(RobotExpression expression) {expressions.add(expression);}@Overridepublic int interpret(RobotContext context) {int totalEnergy = 0;context.addToLog("开始执行序列指令");for (RobotExpression expression : expressions) {totalEnergy += expression.interpret(context);}context.addToLog("序列指令执行完成");return totalEnergy;}@Overridepublic String getDescription() {StringBuilder sb = new StringBuilder("序列指令: [");for (int i = 0; i < expressions.size(); i++) {if (i > 0) sb.append(", ");sb.append(expressions.get(i).getDescription());}sb.append("]");return sb.toString();}
}

4. 上下文类 (Context)

// 上下文类
public class RobotContext {private int x = 0;private int y = 0;private String direction = "北";private List<String> log = new ArrayList<>();private int energyConsumed = 0;public void addToLog(String message) {log.add(message);}public List<String> getLog() {return new ArrayList<>(log);}public void clearLog() {log.clear();}public void addEnergyConsumed(int energy) {this.energyConsumed += energy;}public int getEnergyConsumed() {return energyConsumed;}public String getPosition() {return "(" + x + ", " + y + ")";}public String getDirection() {return direction;}// 更新位置和方向的方法public void updatePosition(int distance) {switch (direction) {case "北": y += distance; break;case "南": y -= distance; break;case "东": x += distance; break;case "西": x -= distance; break;}}public void updateDirection(String newDirection) {this.direction = newDirection;}
}

5. 指令解析器 (Parser)

// 指令解析器
public class RobotInstructionParser {public static RobotExpression parse(String instruction) {if (instruction.startsWith("MOVE")) {int distance = Integer.parseInt(instruction.substring(5));return new MoveExpression(distance);}else if (instruction.startsWith("TURN")) {String dir = instruction.substring(5);return new TurnExpression(dir);}else if (instruction.startsWith("GRAB")) {String obj = instruction.substring(5);return new GrabExpression(obj);}else if (instruction.startsWith("REPEAT")) {String[] parts = instruction.split(" ");int times = Integer.parseInt(parts[1]);String subInstruction = instruction.substring(instruction.indexOf(' ', 7) + 1);RobotExpression subExpression = parse(subInstruction);return new RepeatExpression(times, subExpression);}else if (instruction.startsWith("SEQUENCE")) {SequenceExpression sequence = new SequenceExpression();String[] subInstructions = instruction.substring(9).split(";");for (String subInstruction : subInstructions) {sequence.addExpression(parse(subInstruction.trim()));}return sequence;}throw new IllegalArgumentException("无法解析指令: " + instruction);}
}

6. 客户端代码

public class InterpreterPatternDemo {public static void main(String[] args) {System.out.println("=== 解释器模式演示 - 机器人指令系统 ===\n");// 创建上下文RobotContext context = new RobotContext();// 解析并执行简单指令System.out.println("1. 执行简单指令:");RobotExpression move = RobotInstructionParser.parse("MOVE 10");RobotExpression turn = RobotInstructionParser.parse("TURN 东");RobotExpression grab = RobotInstructionParser.parse("GRAB 箱子");System.out.println("指令: " + move.getDescription());int energy1 = move.interpret(context);System.out.println("消耗能量: " + energy1 + "\n");System.out.println("指令: " + turn.getDescription());int energy2 = turn.interpret(context);System.out.println("消耗能量: " + energy2 + "\n");System.out.println("指令: " + grab.getDescription());int energy3 = grab.interpret(context);System.out.println("消耗能量: " + energy3 + "\n");// 解析并执行复杂指令System.out.println("2. 执行复杂指令:");RobotExpression repeat = RobotInstructionParser.parse("REPEAT 3 MOVE 5");System.out.println("指令: " + repeat.getDescription());context.clearLog();int energy4 = repeat.interpret(context);// 显示执行日志System.out.println("\n执行日志:");for (String logEntry : context.getLog()) {System.out.println("  " + logEntry);}System.out.println("总消耗能量: " + energy4 + "\n");// 解析并执行序列指令System.out.println("3. 执行序列指令:");RobotExpression sequence = RobotInstructionParser.parse("SEQUENCE MOVE 8; TURN 南; MOVE 5; GRAB 物品");System.out.println("指令: " + sequence.getDescription());context.clearLog();int energy5 = sequence.interpret(context);System.out.println("\n执行日志:");for (String logEntry : context.getLog()) {System.out.println("  " + logEntry);}System.out.println("总消耗能量: " + energy5);System.out.println("最终位置: " + context.getPosition());System.out.println("最终方向: " + context.getDirection());System.out.println("\n=== 演示完成 ===");}
}

在Spring的应用

在Spring框架中,解释器模式的应用主要体现在:

  1. SpEL (Spring Expression Language):Spring表达式语言使用解释器模式来解析和求值表达式
  2. 配置文件解析:Spring使用解释器模式解析XML配置文件和注解
  3. 路由表达式:在Spring Integration中,使用解释器模式解析路由表达式
  4. 条件注解:如@Conditional注解使用解释器模式解析条件表达式

总结

解释器模式适用于需要解释执行特定语言的场景,特别是当语言比较简单且执行效率不是关键因素时。它通过将语言的每个规则表示为一个类,使得语言的文法易于改变和扩展。

在机器人指令系统的例子中,我们展示了如何:

  • 定义抽象表达式接口和具体表达式类
  • 实现终结符表达式(基本指令)和非终结符表达式(复合指令)
  • 使用上下文对象维护解释过程中的状态信息
  • 实现指令解析器将字符串指令转换为表达式对象

解释器模式的优点在于它的灵活性和可扩展性,但需要注意它可能导致的类膨胀问题和性能问题。在实际应用中,对于复杂的语言,通常会将解释器模式与编译器技术结合使用。

http://www.hskmm.com/?act=detail&tid=11057

相关文章:

  • trick杂记 例题
  • 代码随想录算法训练营第四天 | leetcode 24
  • 网络流 最小割、费用流
  • DP tricks
  • 碎碎念(十七)
  • OpenCV的一些API的使用
  • 2971:抓住那头牛
  • 高效测试的第一步:5个用例设计基础思维模型
  • MFC Button 控件完全指南:从基础到进阶 - 指南
  • Python笔记总结
  • vulnhub靶机:GoldenEye-v1
  • 8465:马走日
  • 性能调优之NUMA调优
  • 深入解析:SpringMVC静态资源与Servlet容器指南
  • CCPC Online 2025 游寄
  • CentOS 7 容器时遇到了 yum update 报错
  • MIT新论文:数据即上限,扩散模型的关键能力来自图像统计规律,而非复杂架构
  • 基于MATLAB的视频动态目标跟踪检测搭建方案
  • U522155 数据生成(小心电脑)
  • 实用指南:OSG中osgFX库
  • 如何将带有线网卡和无线网卡的台式机作为网关/路由器
  • 2025.9.20——1橙
  • 日期
  • 【GAN网络解惑】面向产品的优化:推理裁剪、蒸馏、INT8/FP8 量化,GAN 的真实延迟如何打下来? - 教程
  • 资本与资本主义
  • 202509_NBWS_encoded_csv
  • 滑雪
  • 守序者的尊严
  • 在Ubuntu22.04平台上交叉编译针对Rv1126架构的GCC13.2.0编译器
  • 深度学习(DBBNet重参数化)