JAVA23种设计模式之解释器模式

  1. 解释器模式
    解释器模式是类的行为模式,给定一个语言,定义他的文法表示,并且定义一个解释器,客户端可以使用这个解释器来解释这个语言中的句子。一般在现实应用中使用的比较少,毕竟相对来说,我们一般不需要自己定义一套自己的语法来解析。其实相对来说,解释器就相当于大脑,把一句话翻译成可以理解的内容。
  2. 解释器模式的示例图
    解释器模式示意图
  3. 解释器模式包含的角色
  • 抽象表达式角色:声明一个所有具体表达式角色都需要实现或者继承的抽象接口。该接口最主要的是一个interpret()方法,一般称为解释操作。
  • 终结符表达式角色:实现了抽象表达式角色所要求的接口,主要是interpret()方法。文法中的每个终结符都有一个具体的终结表达式与之对应,比如一个简单的加法运算a=b+c;在这里面b和c都是终结符,对应的解释b和c的解释器就是终结符表达式。
  • 非终结符表达式角色:文法中每一个规则都需要一个具体的非终结符表达式,一般表示文法中的运算符或者其他关键字,上面的加法运算中"+“就是非终结符。解析”+"的解释器就是一个非终结符表达式。
  • 环境角色:这个角色的任务一般是用来存放文法中各个终结符对应的具体值,比如b,c,我们可以给b赋值100,c赋值为200,这些就需要存放到环境角色中,很多情况下我们使用Map来充当环境角色。
  1. 示例代码:(示例代码引用自《JAVA设计模式(22):行为型-解释器模式(Interpreter)》)
  • 环境角色:
public class Context {
    /**
     * 用于将字符串分解为更小的字符串标记(Token),默认情况下以空格作为分隔符
     */
    private StringTokenizer stringTokenizer;
    /**
     * 当前字符串标记
     */
    private String currentToken;

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

    /**
     * 返回下一个标记
     * @return
     */
    public String nextToken() {
        if (stringTokenizer.hasMoreTokens()){
            currentToken = stringTokenizer.nextToken();
        }else {
            currentToken = null;
        }
        return currentToken;
    }

    /**
     * 返回当前的标记
     * @return
     */
    public String currentToken() {
        return currentToken;
    }

    /**
     * 跳过一个标记
     * @param token
     */
    public void skipToken(String token){
        if (!token.equals(currentToken)) {
            System.err.println("错误提示:" + currentToken + "解释错误!");
        }
        nextToken();
    }

    /**
     * 如果当前的标记是一个数字,则返回对应的数值
     * @return
     */
    public int currentNumber(){
        int number = 0;
        try{
            number = Integer.parseInt(currentToken); //将字符串转换为整数
        }catch(NumberFormatException e) {
            System.err.println("错误提示:" + e);
        }
        return number;
    }
}
  • 抽象表达式角色:
public abstract class Expression {
    /**
     * 声明一个方法用于解释语句
     * @param text
     */
    abstract void interpreter(Context text);

    /**
     * 声明一个方法用于执行标记对应的命令
     */
    public abstract void execute();
}
  • 非终结符表达式角色:
public class ExpressionNode extends Expression {
    private ArrayList<Expression> list = new ArrayList<Expression>();
    @Override
    void interpreter(Context text) {
        while (true){
            if (text.currentToken() == null){
                break;
            }else if (text.currentToken().equals("END")) {
                text.skipToken("END");
                break;
            }else{
                Expression commandExpression = new CommandExpression();
                commandExpression.interpreter(text);
                list.add(commandExpression);
            }
        }
    }
    //循环执行命令集合中的每一条命令
    @Override
    public void execute() {
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            ((Expression)iterator.next()).execute();
        }
    }
}
public class CommandExpression extends Expression {
    private Expression expression;
    @Override
    void interpreter(Context text) {
        if (text.currentToken().equals("LOOP")){
            expression = new LoopCommandExpression();
            expression.interpreter(text);
        }else{
            expression = new PrimitiveCommandExpression();
            expression.interpreter(text);
        }
    }

    @Override
    public void execute() {
        expression.execute();
    }
}
public class LoopCommandExpression extends Expression {
    private int number;
    private Expression commandExpression;
    @Override
    void interpreter(Context text) {
        text.skipToken("LOOP");
        number=text.currentNumber();
        text.nextToken();
        commandExpression = new ExpressionNode();
        commandExpression.interpreter(text);
    }
    @Override
    public void execute() {
        for(int i=0;i<number;i++) {
            commandExpression.execute();
        }
    }
}
  • 终结符表达式角色:
public class PrimitiveCommandExpression extends Expression {
    private String name;
    private String textStr;
    @Override
    void interpreter(Context text) {
        name = text.currentToken();
        text.skipToken(name);
        if (!name.equals("PRINT") && !name.equals("BREAK") && !name.equals ("SPACE")){
            System.err.println("非法命令!");
        }
        if (name.equals("PRINT")){
            textStr = text.currentToken();
            text.nextToken();
        }
    }
    @Override
    public void execute() {
        if (name.equals("PRINT")){
            System.out.print(textStr);}
        else if (name.equals("SPACE")){
            System.out.print(" ");}
        else if (name.equals("BREAK")){
            System.out.println();}
    }
}
  • 测试主函数:
public class Main {
    public static void main(String[] args){
        String text = "LOOP 2 PRINT 杨过 SPACE SPACE PRINT 小龙女 BREAK END PRINT 郭靖 SPACE SPACE PRINT 黄蓉";
        Context context = new Context(text);

        Expression expression = new ExpressionNode();
        expression.interpreter(context);
        expression.execute();
    }
}
  1. 解释器模式的优缺点
    优点:
    可扩展性比较好;增加了新的解释表达式的方式;易于实现简单文法。
    缺点:
    该模式比较难以理解,可利用的场景少,有可能会造成类爆炸,由于该模式采用的事递归,不利于调试。
发布了62 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/system_obj/article/details/88383147