设计模式(JAVA)——Interpreter模式

1. Interpreter模式

解释器模式,语法规则也是类。程序要解决的问题会被用非常简单的"迷你语言"表述出来,用"迷你语言"编写的"迷你程序"把具体问题表述出来。迷你程序需要配合一个"翻译(Interpreter)"的程序来进行解释。

1.1 Interpreter模式的类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E3vFodCG-1575085421717)(./resources/image/23/23-1_Interpreter.png)]

登场的角色

  • AbstractExpression(抽象表达式)
    定义了语法树的共同接口

  • TerminalExpression(终结符表达式)
    对应了BNF中的终结符表达式

  • NonterminalExpress(非终结表达式)
    对应了BNF中的非终结表达式

  • Context(上下文)
    为解释器进行语法解析分析提供了必要的信息。

  • Client(请求者)
    调用解释器解释Context的内容

1.2 示例程序

类一览表

名字说明
Node表示语法树"节点"的类
ProgramNode对应的类
CommandListNode对应的类
CommandNode对应的类
RepeatCommandNode对应的类
PrimitiveCommandNode对应的类
Context表示语法解析上下文的类
Main测试程序行为的类

uml类图(只含继承关系)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EfapfV9k-1575085421718)(./resources/image/23/23-2.png)]

uml类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ke6PwiyU-1575085421719)(./resources/image/23/23-3.png)]

目录和program.txt

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vihg6zG5-1575085421720)(./resources/image/23/23-4.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y7X5gEAF-1575085421723)(./resources/image/23/23-5.png)]

Node类

package xin.ajay.interpreter;

import java.text.ParseException;

/*
<program> ::= program <command list>
<command list> ::= <command>* end
<command> ::= <repeat command> | <primitive command>
<repeat command> ::= repeat <number> <command list>
<primitive command> ::= go | right | left
 */
public abstract class Node {
    public abstract void parse(Context context) throws ParseException;
}

Context类

package xin.ajay.interpreter;

import java.text.ParseException;
import java.util.StringTokenizer;

public class Context {
    private StringTokenizer tokenizer;
    private String currentToken;

    public Context(String text) {
       tokenizer = new StringTokenizer(text);
       nextToken();
    }

    public void skipToken(String token) throws ParseException{
        if(!token.equals(currentToken)){
            throw new ParseException("Warning: "+ token + " is expected,but " + currentToken + " is found",0);
        }
        nextToken();
    }

    public String currentToken() {
        return currentToken;
    }

    public int currentNumber() {
        int number = 0;
        number = Integer.parseInt(currentToken);
        return number;
    }

    public String nextToken() {
        if(tokenizer.hasMoreTokens()){
            currentToken = tokenizer.nextToken();
        }else {
            currentToken = null;
        }
        return currentToken;
    }
}

ProgramNode类

package xin.ajay.interpreter;

import java.text.ParseException;

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 xin.ajay.interpreter;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

public class CommandListNode extends Node{
    private List<Node> list= new ArrayList<>();

    @Override
    public void parse(Context context) throws ParseException {
        while (true){
            if(context.currentToken() ==null){
                throw new ParseException("Missing 'end'",0);
            }else if(context.currentToken().equals("end")){
                context.skipToken("end");
                break;
            }else {
                Node commandNode = new CommandNode();
                commandNode.parse(context);
                list.add(commandNode);
            }
        }
    }

    public String toString(){
        return list.toString();
    }
}

CommandNode类

package xin.ajay.interpreter;

import java.text.ParseException;

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);
        }
    }

    public String toString(){
        return node.toString();
    }
}

RepeatCommandNode类

package xin.ajay.interpreter;

import java.text.ParseException;

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 + "]";
    }
}

PrimitiveCommandNode类

package xin.ajay.interpreter;

import java.text.ParseException;

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",0);
        }
    }

    public String toString(){
        return name;
    }

}

Main类

package xin.ajay.interpreter;

import java.io.*;
import java.text.ParseException;

public class Main {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(Main.class.getClassLoader().getResourceAsStream("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);
            }
            reader.close();

        } catch (IOException | ParseException 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]]]]
鸣谢

GoF《设计模式》和结城浩的《图解设计模式》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值