【设计模式】25.行为型模式-解释器(Interpreter)

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路【设计模式】25.行为型模式-解释器(Interpreter),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

一、描述

给定一个语言,定义它的文法的一种标识,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。解释器模式为自定义语言的设计和实现提供了一种解决方案,它用于定义一组文法规则并通过这组文法规则来解释语言中的句子。

1.角色:

(1)抽象表达式类(AbstractExpression):定义处理文本数据的抽象方法

(2)终点表达式类(TeminalExpression):实现抽象表达式类,为最终的叶子节点类。

(3)非终点表达式类(UnTeminalExpression):实现抽象表达式类,并非为最终的叶子节点。

(4)上下文(Context):包含变量与值的对应关系。

2.类图:

在这里插入图片描述

二、优点

1.易于改变和扩展文法,由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。

2.每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。

3.实现文法比较容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。 
4.增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式,原有表达式类代码无需修改,符合“开闭原则”

三、缺点

1.对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。

2.执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

四、适用场景

1.可以将一个需要解释执行的语言中的句子表示为一个抽象语法树

2.一些重复出现的问题可以用一种简单的语言来进行表达

3.一个语言的文法较为简单

4.执行效率不是关键问题

五、示例

以“计算加减乘除为例”。代码如下:

1.上下文类:

public class Context {
    //存储变量与值的对应关系
    private Map<String, Integer> map = new HashMap<>();

    /**
     * 添加值
     *
     * @param key
     * @param value
     */
    public void addValue(String key, Integer value) {
        map.put(key, value);
    }

    /**
     * 获取值
     */
    public Integer getValue(String key) {
        return map.get(key);
    }
}

2.抽象表达式类

public interface Expression {
    /**
     * 定义处理上下文的接口
     *
     * @param context
     * @return
     */
    Integer interpreter(Context context);
}

3.终端表达式类-变量类

public class Variable implements Expression {
    private String key;

    /**
     * 将变量key值赋值给当前变量
     *
     * @param key
     */
    public Variable(String key) {
        this.key = key;
    }

    /**
     * 根据key获取对应的值
     */
    @Override
    public Integer interpreter(Context context) {
        return context.getValue(key);
    }
}

4.非终端表达式类-加法表达式

public class Add implements Expression {
    private Expression a;
    private Expression b;

    /**
     * 初始化加法符号两侧数据
     *
     * @param a
     * @param b
     */
    public Add(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    /**
     * 处理加法
     *
     * @param context
     * @return
     */
    @Override
    public Integer interpreter(Context context) {
        return a.interpreter(context) + b.interpreter(context);
    }
}

5.非终端表达式-减法表达式

public class Minus implements Expression {
    private Expression a;
    private Expression b;

    /**
     * 初始化减法符号两侧数据
     *
     * @param a
     * @param b
     */
    public Minus(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    /**
     * 处理减法
     *
     * @param context
     * @return
     */
    @Override
    public Integer interpreter(Context context) {
        return a.interpreter(context) - b.interpreter(context);
    }
}

6.非终端表达式-乘法表达式

public class Multiply implements Expression {
    private Expression a;
    private Expression b;

    /**
     * 初始化乘法符号两侧数据
     *
     * @param a
     * @param b
     */
    public Multiply(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    /**
     * 初始化乘法符号两侧数据
     */
    @Override
    public Integer interpreter(Context context) {
        return a.interpreter(context) * b.interpreter(context);
    }
}

7.非终端表达式-除法表达式

public class Division implements Expression {
    private Expression a;
    private Expression b;

    /**
     * 初始化除法符号两侧数据
     *
     * @param a
     * @param b
     */
    public Division(Expression a, Expression b) {
        this.a = a;
        this.b = b;
    }

    /**
     * 处理除法
     */
    @Override
    public Integer interpreter(Context context) {
        return a.interpreter(context) / b.interpreter(context);
    }
}

8.测试

public class Client {
    public static void main(String[] args) {
        //存放变量以及值对应
        Context context = new Context();
        context.addValue("a", 1);
        context.addValue("b", 2);
        context.addValue("c", 3);

        //存放变量
        Variable v1 = new Variable("a");
        Variable v2 = new Variable("b");
        Variable v3 = new Variable("c");

        //将变量添加到运算操作中
        //v1+v2
        Add add = new Add(v1, v2);
        //add - v3 = v1 + v2 - v3
        Minus minus = new Minus(add, v3);

        //计算
        System.out.println("a+b-c=" + minus.interpreter(context));
    }
}

测试结果:
在这里插入图片描述
 大家有没有对这个计算流程感觉迷惑呢?接下来我解释一下这个计算流程。上面计算公式用抽象语法树表示:
 在这里插入图片描述
  计算顺序为:

(1) v1 + v2 = add

(2) add – v3 = v1 + v2 – v3

(3) 最终通过终端表达式v1,v2,v3,将变量与值换算为context中配置的具体数值,从而计算出最终结果。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/158088.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!