软件设计模式之路-----解释器模式

软件设计模式之路-----解释器模式

 

这是学习的最后一种解释器了,长话短说。解释器模式用来解决特定类型的问题发生频率比较高,而且有一定的相似性和规律性。例如计算器。这种模式在实际开发中使用的可能性比较少。但也有学习的必要,因为这能帮助我们看懂一些源码。例如Spring EL表达式、正则表达式。

解释器(Interpreter)模式的定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。

优点:

  • 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。 
  • 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。

缺点:

  • 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。会引起类膨胀。
  • 解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。 
  • 可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。

模式的结构与实现

结构

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

实现

实现场景:用解释器模式解释表达式,来实现计算器功能(只包含加减法)

package com.wly.DesignPatterns;

import java.util.Stack;

/**
 * @program: StudyDome
 * @author: yuanzhang
 * @create: 2021-01-26 15:22
 **/
public class InterpreterPattern {
    public static void main(String[] args) {
        CalculateUtil calculateUtil = new CalculateUtil();
        String expression = "9+8+7-8-7-6";
        calculateUtil.parse(expression);
        float result = calculateUtil.calculate();
        System.out.println(expression+"="+result);

    }
}
/** 
 * @Annotation:抽象表达式
 * @Author: yuanzhang
 * @Date:  15:23
 */ 
interface AbstractExpression{
    public float interpret();
}
/**
 * @Annotation:终结表达式:存储数字
 * @Author: yuanzhang
 * @Date:  15:56
 */
class NumberExpression implements AbstractExpression{
    private float number;

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

    @Override
    public float interpret() {
        return number;
    }
}
/**
 * @Annotation:非终结表达式:加法
 * @Author: yuanzhang
 * @Date:  15:56
 */
class AddExpression implements AbstractExpression{
    private AbstractExpression e1,e2;

    public AddExpression(AbstractExpression e1, AbstractExpression e2) {
        this.e1 = e1;
        this.e2 = e2;
    }

    @Override
    public float interpret() {
        //执行加法运算
        return e1.interpret()+e2.interpret();
    }
}
/**
 * @Annotation:非终结表达式:减法
 * @Author: yuanzhang
 * @Date:  15:59
 */
class SubtractionExpression implements AbstractExpression{
    private AbstractExpression e1,e2;

    public SubtractionExpression(AbstractExpression e1, AbstractExpression e2) {
        this.e1 = e1;
        this.e2 = e2;
    }

    @Override
    public float interpret() {
        //执行减法运算
        return e1.interpret()-e2.interpret();
    }
}
class CalculateUtil{
    private AbstractExpression expression;

    public void parse(String expression){
        String[] strings = expression.split("");
        Stack<AbstractExpression> stack = new Stack <AbstractExpression>();
        for (int i = 0; i < strings.length; i++) {
            //如果是加法操作符
            if (strings[i].equals("+")){
                //获取栈顶的数据
                AbstractExpression e1 = stack.pop();
                //获取下一个表达式
                AbstractExpression e2 = new NumberExpression(strings[++i]);
                //判断下一个数据
                //进行加法计算
                stack.push(new AddExpression(e1,e2));
            }else if (strings[i].equals("-")){
                //减法操作符
                //获取栈顶的数据
                AbstractExpression e1 = stack.pop();
                //获取下一个表达式
                AbstractExpression e2 = new NumberExpression(strings[++i]);
                //进行加法计算
                stack.push(new SubtractionExpression(e1,e2));
            }else{
                stack.push(new NumberExpression(strings[i]));
            }
        }
        //将最后结果保留
        this.expression = stack.pop();
    }
    public float calculate(){
        return expression.interpret();
    }
}

输出:

9+8+7-8-7-6=3.0
上一篇:ProgrammingContestChallengeBook


下一篇:获取搜索二叉树两个错误节点