行为型模式(三):解释器模式

1、模式的定义与特点

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

这里提到的文法和句子的概念同编译原理中的描述相同,“文法”指语言的语法规则,而“句子”是语言集中的元素。
例如,汉语中的句子有很多,“我是中国人”是其中的一个句子,可以用一棵语法树来直观地描述语言中的句子。

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

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

2、模式的结构

解释器模式常用于对简单语言的编译或分析实例中。

解释器模式的结构与组合模式相似,不过其包含的组成元素比组合模式多,而且组合模式是对象结构型模式,而解释器模式是类行为型模式。

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

在这里插入图片描述

图1 解释器模式的结构图

3、模式的应用场景

1、当语言的文法较为简单,且执行效率不是关键问题时。
2、当问题重复出现,且可以用一种简单的语言来进行表达时。
3、当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。

注意:
解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。如果碰到对表达式的解释,在Java中可以用Expression4J或Jep等来设计。

4、模式的实现

在这里插入图片描述

图2 示例代码结构

抽象表达式角色:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 * 抽象表达式角色
 */
abstract class Expression {
    public abstract int interpret(Context context);
}

上下文角色:

package com.example.designpattern.interpreter;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 * @date 2020/8/4
 * 上下文角色
 * 用来存储变量的值
 */
class Context {
    private Map<VariableExpression, Integer> map = new HashMap<>();

    /**
     * 向环境对象添加变量的值
     */
    public void add(VariableExpression v, Integer value) {
        map.put(v, value);
    }

    /**
     * 给定一个变量名,获取它的值
     */
    public Integer lookUpValue(VariableExpression v){
        return map.get(v);
    }
}

终结符表达式角色1:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 * 终结符表达式角色,是一种具体的表达式
 * 表示变量的表达式
 */
class VariableExpression extends Expression {
    @Override
    public int interpret(Context context) {
        return context.lookUpValue(this);
    }
}

终结符表达式角色2:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 * 终结符表达式角色
 * 用来封装常量数字
 */
class ConstantExpression extends Expression {
    private int i;

    public ConstantExpression(int i) {
        this.i = i;
    }

    @Override
    public int interpret(Context context) {
        return i;
    }
}

非终结符表达式1:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 * 非终结符表达式
 * 用来解释+运算
 */
class AddExpression extends Expression {
    private Expression left;
    private Expression right;

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

    @Override
    public int interpret(Context context) {
        return left.interpret(context) + right.interpret(context);
    }
}

非终结符表达式2:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 * 非终结符表达式
 * 用来解释-运算
 */
class SubtractExpression extends Expression {
    private Expression left;
    private Expression right;

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

    @Override
    public int interpret(Context context) {
        return left.interpret(context) - right.interpret(context);
    }
}

非终结符表达式3:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 * 非终结符表达式
 * 用来解释*运算
 */
class MultiplyExpression extends Expression {
    private Expression left;
    private Expression right;

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

    @Override
    public int interpret(Context context) {
        return left.interpret(context) * right.interpret(context);
    }
}

非终结符表达式4:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 * 非终结符表达式
 * 用来解释/运算
 */
class DivisionExpression extends Expression {
    private Expression left;
    private Expression right;

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

    @Override
    public int interpret(Context context) {
        try {
            return left.interpret(context) / right.interpret(context);
        } catch (Exception e) {
            System.out.println("除数不能为0");
            return -1;
        }
    }
}

调用:

package com.example.designpattern.interpreter;

/**
 * @author Administrator
 * @date 2020/8/4
 */
class Client {
    public static void main(String[] args) {
        // 1、定义出一个表达式。  如a*b/(c+3),本例中赋值a=5  b=7  c=2
        VariableExpression a = new VariableExpression();
        VariableExpression b = new VariableExpression();
        VariableExpression c = new VariableExpression();

        //常量3
        ConstantExpression d = new ConstantExpression(3);

        //2、将变量放入环境
        Context context = new Context();
        context.add(a, 5);
        context.add(b, 7);
        context.add(c, 2);

        //3、将a*b/(c+3)封装为一个表达式对象
        Expression ex = new DivisionExpression(
                new MultiplyExpression(a, b),
                new AddExpression(c, d)
        );

        int result = ex.interpret(context);

        System.out.println("a=5,b=7,c=2 表达式a*b/(c+3)的结果是:" + result);
    }
}

在这里插入图片描述

图3 测试结果

5、PPT素材

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

微信公众号: TechU
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值