• 行为型设计模式


    基本介绍

    解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。

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

    该模式对于复杂的场景实现起来比较困难,实际应用较少,大家了解即可。

    模式结构

    Context(环境角色):声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret() 方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器 TerminalExpression 和非终结符解释器 NonterminalExpression 完成。

    AbstractExpression(抽象解释器):实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面 R1 和 R2 就是终结符,对应的解析 R1 和 R2 的解释器就是终结符表达式。

    TerminalExpression(终结符表达式):文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式 R=R1+R2 中,+ 就是非终结符,解析 + 的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

    NoterminalExpression(非终结符表达式):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如 R=R1+R2,我们给 R1 赋值 100,给 R2 赋值 200。这些信息需要存放到环境角色中,很多情况下我们使用 Map 来充当环境角色就足够了。

    举例说明

    使用解释器模式实现数字的加减法

    1、抽象解释器

    /**
     * 抽象解释器
     */
    public abstract class AbstractExpression {
        public abstract int interpret(Context context);
    }
    

    2、非终结符表达式

    /**
     * 非终结表达式:加法
     */
    public class AddExpression extends AbstractExpression {
        private final AbstractExpression left;
        private final AbstractExpression right;
    
        public AddExpression(AbstractExpression left, AbstractExpression right) {
            this.left = left;
            this.right = right;
        }
    
        @Override
        public int interpret(Context context) {
            return left.interpret(context) + right.interpret(context);
        }
    }
    
    /**
     * 非终结表达式:减法
     */
    public class SubExpression extends AbstractExpression {
        private final AbstractExpression left;
        private final AbstractExpression right;
    
        public SubExpression(AbstractExpression left, AbstractExpression right) {
            this.left = left;
            this.right = right;
        }
    
        @Override
        public int interpret(Context context) {
            return left.interpret(context) - right.interpret(context);
        }
    }
    

    3、终结表达式

    /**
     * 终结表达式:变量
     */
    public class Variable extends AbstractExpression {
        private final String key;
    
        public Variable(String key) {
            this.key = key;
        }
    
        @Override
        public int interpret(Context context) {
            return context.getValue(key);
        }
    }
    

    4、环境角色

    /**
     * 环境上下文
     */
    public class Context {
        private final Map<String, Integer> valueMap = new HashMap<>();
    
        public void addValue(final String key, final int value) {
            valueMap.put(key, value);
        }
    
        public int getValue(final String key) {
            return valueMap.get(key);
        }
    
        public Map<String, Integer> getValueMap() {
            return valueMap;
        }
    }
    

    5、测试类

    public class Client {
        @Test
        public void test(){
            Context context = new Context();
    
            context.addValue("a", 6);
            context.addValue("b", 9);
            context.addValue("c", 1);
    
            Variable a = new Variable("a");
            Variable b = new Variable("b");
            Variable c = new Variable("c");
    
            AbstractExpression addValue = new AddExpression(a, b);
            AbstractExpression subValue = new SubExpression(addValue, c);
    
            System.out.println(context.getValueMap());
            System.out.println("a + b - c = " + subValue.interpret(context));
        }
    }
    

    6、运行结果

    {a=6, b=9, c=1}
    a+b-c=14
    

    模式分析

    优点:

    • 可扩展性比较好,灵活
    • 增加了新的解释表达式的方式
    • 易于实现简单文法

    缺点:

    • 可利用场景比较少
    • 对于复杂的文法比较难维护
    • 解释器模式会引起类膨胀
    • 解释器模式采用递归调用方法

    适用场景:

    • 有一个简单的语法规则,比如一个 sql 语句,如果我们需要根据 sql 语句进行 rm 转换,就可以使用解释器模式来对语句进行解释。
    • 一些重复发生的问题,比如加减乘除四则运算,但是公式每次都不同,有时是 a+b-cd,有时是 ab+c-d,等等等等个,公式千变万化,但是都是由加减乘除四个非终结符来连接的,这时我们就可以使用解释器模式。

    参考

  • 相关阅读:
    一篇与面试官和蔼交流的深入了解JVM(JDK8)
    逆向工程,调试Hello World !程序(更新中)
    SpingBoot + Dubbo + Zookeeper实现简单分布式开发的应用
    Vue Axios 切片上传文件含实时进度
    Vue入门——常见指令及其详细代码示例
    女儿说要看烟花,但是政府规定不能放,程序员爸爸默默的拿起了键盘,程序员就是要为所欲为!
    逆向工程,调试Hello World !程序(更新中)
    python学习初始函数
    Python学习之装饰器
    Python学习之装饰器进阶
  • 原文地址:https://www.cnblogs.com/songjilong/p/12872564.html
Copyright © 2020-2023  润新知