设计模式学习笔记——解释器(Interpreter)模式

    xiaoxiao2021-03-30  33

    设计模式学习笔记——解释器(Interpreter)模式

    @(设计模式)[设计模式, 解释器模式, Interpreter]

    设计模式学习笔记解释器Interpreter模式 基本介绍解释器案例 类图实现代码 Node抽象类ParseException类ProgramNode类CommandListNode类CommandNode类RepeatCommandNode类PrimitiveCommandNode类Context类测试类运行结果 解释器模式中的角色 AbstractExpression抽象表达式TerminalExpression终结符表达式NonterminalExpression非终结符表达式Context文脉上下文Client请求者类图

    基本介绍

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

    解释器案例

    类图

    实现代码

    Node抽象类

    package com.pc.interpreter.example; /** * 节点类 */ public abstract class Node { /** * 解析 * * @param context 上下文 * @throws ParseException 解析异常 */ public abstract void parse(Context context) throws ParseException; }

    ParseException类

    package com.pc.interpreter.example; /** * 解析异常类 */ public class ParseException extends Exception { public ParseException(String msg) { super(msg); } }

    ProgramNode类

    package com.pc.interpreter.example; /** * 程序节点类 * <program> ::= program <command list> */ public class ProgramNode extends Node { /** * 命令列表节点 */ private Node commandListNode; @Override public void parse(Context context) throws ParseException { context.skipToken("program"); commandListNode = new CommandListNode(); commandListNode.parse(context); } @Override public String toString() { return "[program " + commandListNode + "]"; } }

    CommandListNode类

    package com.pc.interpreter.example; import java.util.ArrayList; /** * 命令列表节点类 * <command list> ::= <command>* end */ public class CommandListNode extends Node { /** * 命令列表 */ private ArrayList list = new ArrayList(); @Override public void parse(Context context) throws ParseException { while (true) { if (context.currentToken() == null) { throw new ParseException("Missing 'end'"); } else if (context.currentToken().equals("end")) { context.skipToken("end"); break; } else { Node commandNode = new CommandNode(); commandNode.parse(context); list.add(commandNode); } } } @Override public String toString() { return list.toString(); } }

    CommandNode类

    package com.pc.interpreter.example; /** * 命令节点类 * <command> ::= <repeat command> | <primitive command> */ public class CommandNode extends Node { /** * 节点 */ private Node node; @Override public void parse(Context context) throws ParseException { if (context.currentToken().equals("repeat")) { node = new RepeatCommandNode(); node.parse(context); } else { node = new PrimitiveCommandNode(); node.parse(context); } } @Override public String toString() { return node.toString(); } }

    RepeatCommandNode类

    package com.pc.interpreter.example; /** * 重复命令节点类 * <repeat command> ::= repeat <number> <command list> */ public class RepeatCommandNode extends Node { /** * 重复次数 */ private int number; /** * 命令列表节点 */ private Node commandListNode; @Override public void parse(Context context) throws ParseException { context.skipToken("repeat"); number = context.currentNumber(); context.nextToken(); commandListNode = new CommandListNode(); commandListNode.parse(context); } @Override public String toString() { return "[repeat " + number + " " + commandListNode + "]"; } }

    PrimitiveCommandNode类

    package com.pc.interpreter.example; /** * 原始命令节点类 * <primitive command> ::= go | right | left */ public class PrimitiveCommandNode extends Node { /** * 名字 */ private String name; @Override public void parse(Context context) throws ParseException { name = context.currentToken(); context.skipToken(name); if (!name.equals("go") && !name.equals("right") && !name.equals("left")) { throw new ParseException(name + " is undefined"); } } @Override public String toString() { return name; } }

    Context类

    package com.pc.interpreter.example; import java.util.StringTokenizer; /** * 上下文类 */ public class Context { /** * 分词器 */ private StringTokenizer tokenizer; /** * 当前符号 */ private String currentToken; public Context(String text) { this.tokenizer = new StringTokenizer(text); this.nextToken(); } /** * 返回下一个符号 * * @return 下一个符号 */ public String nextToken() { if (tokenizer.hasMoreTokens()) { this.currentToken = this.tokenizer.nextToken(); } else { this.currentToken = null; } return this.currentToken; } /** * 返回当前符号 * * @return 当前符号 */ public String currentToken() { return this.currentToken; } /** * 跳过指定符号 * * @param token 指定符号 * @throws ParseException 解析异常 */ public void skipToken(String token) throws ParseException { if (!token.equals(this.currentToken)) { throw new ParseException("Warning: " + token + " is expected, but " + currentToken + " is found."); } this.nextToken(); } /** * 解析数值 * * @return 数值 * @throws ParseException 解析异常 */ public int currentNumber() throws ParseException { int number = 0; try { number = Integer.parseInt(currentToken); } catch (NumberFormatException e) { throw new ParseException("Warning: " + e); } return number; } }

    测试类

    package com.pc.interpreter.example.test; import com.pc.interpreter.example.Context; import com.pc.interpreter.example.Node; import com.pc.interpreter.example.ProgramNode; import org.junit.Test; import java.io.BufferedReader; import java.io.FileReader; /** * Interpreter Tester. * * @author Switch * @version 1.0 */ public class InterpreterTest { /** * 测试解释器模式 */ @Test public void testInterpreter() { try { BufferedReader reader = new BufferedReader(new FileReader(System.getProperty("user.dir") + "/src/main/java/com/pc/interpreter/example/program.txt")); String text; while ((text = reader.readLine()) != null) { System.out.println("text = \"" + text + "\""); Node node = new ProgramNode(); node.parse(new Context(text)); System.out.println("node = " + node); } } catch (Exception e) { e.printStackTrace(); } } }

    运行结果

    text = "program end" node = [program []] text = "program go end" node = [program [go]] text = "program go right go right go right go right end" node = [program [go, right, go, right, go, right, go, right]] text = "program repeat 4 go right end end" node = [program [[repeat 4 [go, right]]]] text = "program repeat 4 repeat 3 go right go left end right end end" node = [program [[repeat 4 [[repeat 3 [go, right, go, left]], right]]]]

    解释器模式中的角色

    AbstractExpression(抽象表达式)

    AbstractExpression角色定义了语法树节点的共同接口(API)。在案例中,由Node类扮演此角色。在案例中,共同接口(API)的名字是parse,不过在类图中它的名字是interpreter。

    TerminalExpression(终结符表达式)

    TerminalExpression角色对应BNF中的终结特表达式。在案例中,由PrimitiveCommandNode类扮演此角色。

    NonterminalExpression(非终结符表达式)

    NonterminalExpression角色对应BNF中的非终结符表达式。在案例中,由ProgramNode类、CommandNode类、RepeatCommandNode类和CommandListNode 类扮演此角色。

    Context(文脉、上下文)

    Context 角色为解释器进行语法解析提供了必要的信息。在案例中,由Context 类扮演此角色。

    Client(请求者)

    为了推导语法树, C li ent 角色会调用TerminalExpression 角色和Nonterm inalExpress i on 角色。在案例中,由Ma 工n 类扮演此角色。

    类图

    GitHub:DesignPatternStudy

    ——————参考《图解设计模式》

    转载请注明原文地址: https://ju.6miu.com/read-665196.html

    最新回复(0)