Java设计模式(二十三)行为型- 解释器模式 interpreter pattern(史上最全解释器模式)与使用场景以及优缺点

  1. 解释器模式 interpreter pattern

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

特征:为了解释一种语言,而为语言创建的解释器。

解释器模式包含以下主要角色:

  • 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
  • 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
  • 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
  • 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
  • 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

1.1 代码实现

下面以简单的加减乘除为例子实现解释器模式:

// 抽象角色 定义解释器
public interface Expression {
    int interpret();
}
@AllArgsConstructor
public class NumberTerminal implements Expression {
    private int number;
    @Override
    public int interpret() {
        return this.number;
    }
}
// 非终结表达式(抽象类)
@AllArgsConstructor
public abstract class NonTerminal implements Expression {
    protected Expression left;
    protected Expression right;
}
// 非终结表达式(加法)
public class PlusNonTerminal extends NonTerminal implements Expression {
    public PlusNonTerminal(Expression left, Expression right) {
        super(left, right);
    }
    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}
// 非终结表达式(减法)
public class MinusNonTerminal extends NonTerminal implements Expression {
    public MinusNonTerminal(Expression left, Expression right) {
        super(left, right);
    }
    @Override
    public int interpret() {
        return left.interpret() - right.interpret();
    }
}
// 非终结表达式(乘法)
public class MclNonTerminal extends NonTerminal implements Expression {
    public MclNonTerminal(Expression left, Expression right) {
        super(left, right);
    }
    @Override
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}
// 非终结表达式(除法)
public class DivisionNonTerminal extends NonTerminal implements Expression {
    public DivisionNonTerminal(Expression left, Expression right) {
        super(left, right);
    }
    @Override
    public int interpret() {
        return left.interpret() / right.interpret();
    }
}
// 计算器类(实现运算逻辑)
public class Cal {
    private Expression left;
    private Expression right;
    private Integer result;
    public Cal(String expression) {
        this.parse(expression);
    }
    private Integer parse(String expression) {
        // 获取表达式元素
        String [] elements = expression.split(" ");
        for (int i = 0; i < elements.length; i++) {
            String element = elements[i];
            // 判断是否是运算符号
            if (OperatorUtils.isOperator(element)) {
                // 运算符号的右边就是右终结符
                right = new NumberTerminal(Integer.valueOf(elements[++i]));
                //计算结果
                result = OperatorUtils.getNonTerminal(left, right, element).interpret();
                // 计算结果重新成为左终结符
                left = new NumberTerminal(result);
            } else {
                left = new NumberTerminal(Integer.valueOf(element));
            }
        }
        return result;
    }
    public Integer cal() {
        return result;
    }
 
}
// 操作工具类
public class OperatorUtils {
    // 判断是不是非终结符
    public static boolean isOperator(String symbol) {
        return symbol.equals("+") || symbol.equals("-") || symbol.equals("*")|| symbol.equals("/");
    }
    // 简单工厂
    public static NonTerminal getNonTerminal(Expression left, Expression right, String symbol) {
        if (symbol.equals("+")) {
            return new PlusNonTerminal(left, right);
        } else if (symbol.equals("-")) {
            return new MinusNonTerminal(left, right);
        } else if (symbol.equals("*")) {
            return new MclNonTerminal(left, right);
        } else if (symbol.equals("/")) {
            return new DivisionNonTerminal(left, right);
        }
        return null;
    }
}
    // 测试
    // PS:此处进行的逻辑仅仅实现从左到右运算,并没有先乘除后加减的逻辑
    public static void main(String[] args) {
        System.out.println(new Cal("10 + 20 - 40 * 60").cal()); // -600
        System.out.println(new Cal("20 + 50 - 60 * 2").cal()); // 20
    }

1.2 Spring中的解释器模式

public static void main(String[] args) {
        ExpressionParser expressionParser = new SpelExpressionParser();
        org.springframework.expression.Expression expression = expressionParser.parseExpression("10 + 20 + 30 * 4");
        Integer value = expression.getValue(Integer.class);
        System.out.println(value); // 150
        expression = expressionParser.parseExpression("(10+20+30)*4");
        value = expression.getValue(Integer.class);
        System.out.println(value); // 240
    }

可以看到Spring中解释器写的是比较完善的,不仅有先乘除后加减和先括号进行运算的日常计算规则,而且对于空格也并没有要求,仅需要写出完整的表达式即可运算出来。

1.3 总结

适用场景:

  • 一些重复出现的问题可以用一种简单的语言来进行表述。
  • 一个简单语法需要解释的场景。

优点:

  • 扩展性强:在解释器模式中由于语法是由很多类表示的,当语法规则更改时,只需修改相应的非终结符表达式即可;若扩展语法时,只需添加相应非终结符类即可。
  • 增加了新的解释表达式的方式。
  • 易于实现文法:解释器模式对应的文法应当是比较简单且易于实现的,过于复杂的语法并不适合使用解释器模式。

缺点:

  • 语法规则较复杂时,会引起类膨胀。
  • 执行效率比较低
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

angle⠀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值