设计模式-解释器模式

问题背景

通过解释器模式来实现一个表达式的加减运算
例如:在我们先输入一个表达式:a+b+c-d+e,然后输入a,b,c,d,e的值,最终得到结果
在这里插入图片描述

解释器模式

基本介绍

解释器:
就是我们给一个特定的规则,然后我们来解释使用这个规则的输入,最终得到一个结果

解释器模式:
解释器模式就是给了我们一个框架,按照这个框架我们就能开发一个解释器

原理类图

在这里插入图片描述
1)AbstractExpression抽象类,是一个解释器抽象类,所有解释器都要继承它
2)TerminalExpression类,是终结表达式,就是就一个链路中,我们这个结点是知道结果的,不需要等待其他链路计算后才能得到结果,或者说我们这个节点是确定的。
3)NonTerminalExpression类,是非中介表达式,是在这个链路中我们这个表达式的结构是不确定的,需要依赖其他节点
4)Context类,是全局上下文,它保存了解释器之外的全局信息

使用解释器模式来解决问题

UML类图

在这里插入图片描述
1)Context是全局上下文,保存我们输入的表达式中字符对应的值
2)Expression是解释器抽象类
3)VarExpression是终结点解释器,解析表达式中的字符,例如:a+b,那就是解析a和b的数值是多少
4)SysmbolExpression是非终结点表达式,它用来解析左右表达式的运算
5)SubExpression是减法表达式,解析左右表达式相减的结果
6)AddExpression是加法表达式,解析左右表达式相加的结果
7)Calculator是计算器类,用来将表达式生成解析器链路

代码示例

/**
 * 解释器抽象类
 */
public abstract class Expression {

    /**
     * 解析器必须要实现的解析方法
     *
     * @param context
     * @return
     */
    public abstract int interpreter(Context context);
}
/**
 * 全局上下文
 */
public class Context {

    private Map<String, Integer> map = new HashMap<>();

    public Integer getValue(String key) {
        return map.get(key);
    }

    public void setValue(String key, Integer value) {
        map.put(key, value);
    }
}
/**
 * 终结表达式
 *
 * 解释表达式中的数值字符
 *
 * 例如:a = 10,就得到a的数值10
 */
public class VarExpression extends Expression{

    private String key;

    public VarExpression(String key) {
        this.key = key;
    }

    @Override
    public int interpreter(Context context) {

        // 得到这个值对应的数值,返回
        return context.getValue(this.key);
    }
}
/**
 * 非终结表达式
 *
 * 解释表达式中的运算符
 *
 * 对于加减运算,只能是对运算符左右两边的表达式链进行计算
 *
 */
public abstract class SymbolExpression extends Expression{
    /**
     * 左表达式
     */
    private Expression left;

    /**
     * 右表达式
     */
    private Expression right;

    public SymbolExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    public Expression getLeft() {
        return left;
    }

    public void setLeft(Expression left) {
        this.left = left;
    }

    public Expression getRight() {
        return right;
    }

    public void setRight(Expression right) {
        this.right = right;
    }

    /**
     * 交给具体运算符的子类来实现
     *
     * @param context
     * @return
     */
    @Override
    public abstract int interpreter(Context context);
}
/**
 * 减法
 */
public class SubExpression extends SymbolExpression{
    
    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Context context) {
        // 减法 左表达式减去右表达式
        return super.getLeft().interpreter(context) - super.getRight().interpreter(context);
    }
}
/**
 * 加法
 *
 */
public class AddExpression extends SymbolExpression{

    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    @Override
    public int interpreter(Context context) {
        // 加法,所以就将左表达式和右表达式的值相加
        return super.getLeft().interpreter(context) + super.getRight().interpreter(context);
    }
}
/**
 * 解析输入的表达式,生成解释器链路
 */
public class Calculator {
    /**
     * 生成解释器链路
     *
     * @param expStr
     */
    public static Expression getExpression(String expStr) {
        // 使用栈来安排解释器结点的先后顺序
        Stack<Expression> stack = new Stack<>();
        // 输入表达式转为字符数组
        char[] charArray = expStr.toCharArray();

        Expression left;
        Expression right;
        // 遍历输入的表达式
        for (int i = 0; i < charArray.length; i++) {
            switch (charArray[i]) {
                case '+':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new AddExpression(left, right));
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new SubExpression(left, right));
                    break;
                default:
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
                    break;
            }
        }
        return stack.pop();
    }
}
public class Client {
    public static void main(String[] args) throws IOException {
        // 输入表达式
        String expStr = getExpStr();
        // 得到表达式符号对应的值
        Context context = getValue(expStr);
        // 生成解释器链路
        Expression expression = Calculator.getExpression(expStr);
        // 通过解释器计算结果
        int result = expression.interpreter(context);
        System.out.println("运算结果:" + expStr + "=" + result);
    }

    private static String getExpStr() throws IOException {
        System.out.println("请输入表达式:");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }

    private static Context getValue(String expStr) throws IOException {
        Context context = new Context();
        for (char c : expStr.toCharArray()) {
            if (c != '+' && c != '-') {
                System.out.println("请输入字符"+c+"的值:");
                String value = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                context.setValue(String.valueOf(c), Integer.valueOf(value));
            }
        }
        return context;
    }
}

运行结果

在这里插入图片描述

注意事项和细节

1)当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程序具有良好的扩展性
2)应用场景:编译器、运算表达式计算、正则表达式、机器人等
3)使用解释器可能带来的问题: 解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值