java设计模式-解释器模式

解释器模式

解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

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

为了解释一种语言,而为语言创建的解释器

模式和结构定义

在这里插入图片描述

  • 抽象解释器(AbstractExpression/Expression):声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器NonterminalExpression完成。
  • 终结符表达式(TerminalExpression):实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
  • 非终结符表达式(NonterminalExpression):文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
  • 环境角色(Context):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

应用实例

实现一个简单的计算表达式解释器。
表达式:6 100 11 + *
先计算: 100 + 11 = 111
再把上一个计算的结果继续加入计算: 111 * 6 = 666

在这里插入图片描述

  • Interpreter:解释器接口
  • MultiInterpreter:乘法解释器实现
  • AddInterpreter:加法解释器实现
  • NumberInterpreter:数字转换解释器实现
  • OperatorUtil:操作工具类
  • ExpressionParser:解析表达式,根据规则选择执行的解析器进行解析
  • TestMain:测试方法

解释器接口

/**
 * 解释器接口
 *
 * @author shengyong.huang
 * @date 2020-07-25
 */
public interface Interpreter {
    int interpret();
}

加法解释器和乘法解释器实现

/**
 * 加法解释器
 *
 * @author shengyong.huang
 * @date 2020-07-25
 */
public class AddInterpreter implements Interpreter {

    private Interpreter firstExpression, secondExpression;

    public AddInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
        this.firstExpression = firstExpression;
        this.secondExpression = secondExpression;
    }

    @Override
    public int interpret() {
        return this.firstExpression.interpret() + this.secondExpression.interpret();
    }

    @Override
    public String toString() {
        return "+";
    }
}

/**
 * 乘法解释器
 *
 * @author shengyong.huang
 * @date 2020-07-25
 */
public class MultiInterpreter implements Interpreter {
    private Interpreter firstExpression, secondExpression;

    public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpression) {
        this.firstExpression = firstExpression;
        this.secondExpression = secondExpression;
    }

    @Override
    public int interpret() {
        return this.firstExpression.interpret() * this.secondExpression.interpret();
    }

    @Override
    public String toString() {
        return "*";
    }
}

数字转换解释器

/**
 * 数字转换解释器
 *
 * @author shengyong.huang
 * @date 2020-07-25
 */
public class NumberInterpreter implements Interpreter {
    private int number;

    public NumberInterpreter(int number) {
        this.number = number;
    }

    public NumberInterpreter(String number) {
        this.number = Integer.parseInt(number);
    }

    @Override
    public int interpret() {
        return this.number;
    }
}

解析表达式,根据规则选择执行的解析器进行解析

/**
 * 解析表达式,根据规则选择执行的解析器进行解析
 *
 * @author shengyong.huang
 * @date 2020-07-25
 */
public class ExpressionParser {

    private Stack<Interpreter> stack = new Stack<>();

    public int parse(String str) {
        String[] stringArray = str.split(" ");
        for (String symbol : stringArray) {
            if (!OperatorUtil.isOperator(symbol)) {
                Interpreter numberExpression = new NumberInterpreter(symbol);
                stack.push(numberExpression);
                System.out.println(String.format("入栈: %d", numberExpression.interpret()));
            } else {
                // 运算符合,可以计算
                Interpreter first = stack.pop();
                Interpreter second = stack.pop();
                System.out.println(String.format("出栈: %d 和 %d", first.interpret(), second.interpret()));
                Interpreter operator = OperatorUtil.getExpressionObject(first, second, symbol);
                System.out.println(String.format("运算符号: %s", operator));
                int result = operator.interpret();
                NumberInterpreter resultExpression = new NumberInterpreter(result);
                stack.push(resultExpression);
                System.out.println(String.format("阶段结果入栈: %d", resultExpression.interpret()));
            }
        }
        int result = stack.pop().interpret();
        return result;
    }
}

操作工具类

/**
 * 操作工具类
 * @author shengyong.huang
 * @date 2020-07-25
 */
public class OperatorUtil {
    public static boolean isOperator(String symbol) {
        return ("+".equals(symbol) || "*".equals(symbol));
    }

    public static Interpreter getExpressionObject(Interpreter first, Interpreter second, String symbol) {
        if ("+".equals(symbol)) {
            return new AddInterpreter(first, second);
        } else if ("*".equals(symbol)) {
            return new MultiInterpreter(first, second);
        } else {
            return null;
        }
    }

}

测试方法

/**
 * 测试方法
 *
 * @author shengyong.huang
 * @date 2020-07-25
 */
public class TestMain {

    public static void main(String[] args) {
        String inputStr = "6 100 11 + *";
        ExpressionParser expressionParser = new ExpressionParser();
        int result = expressionParser.parse(inputStr);
        System.out.println("解释器计算结果: " + result);
    }
}

结果展示

入栈: 6
入栈: 100
入栈: 11
出栈: 11 和 100
运算符号: +
阶段结果入栈: 111
出栈: 111 和 6
运算符号: *
阶段结果入栈: 666
解释器计算结果: 666

优点和不足

优点

  • 语法由很多类表示,容易改变及扩展此"语言"

缺点

  • 可利用场景比较少。
  • 对于复杂的文法比较难维护。
  • 解释器模式会引起类膨胀。
  • 当语法规则数目太多时,增加了系统复杂度

使用场景

  • 某个特定类型问题发生频率足够高
  • spring中的ExpressionParser,表达式解析器

补充

参考:
https://juejin.im/post/5c39840f5188252538063122

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值