设计模式—解释器模式详解《二》

解释器模式是类的行为模式,给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器,客户端可以使用这个解释器来解释这个语言中的句子。为了加深对于解释器模式的理解,大家可以先看我的第一篇设计模式—解释器模式详解《一》

意图

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

用途

对于一些固定文法构建一个解释句子的解释器。

何时使用

如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

解决方案

构件语法树,定义终结符与非终结符。

关键代码

构件环境类,包含解释器之外的一些全局信息,本文案例适用HashMap。

UML类图

在这里插入图片描述

主要角色

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

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

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

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

代码demo

demo场景:基于某种语言(我这里用的是Java)模拟解释加减乘除表达式的解释和计算,本文测试的场景:(a*b)/(a-b+c)。

创建抽象解释器

//抽象解释器
public abstract class AbstractExpression {

    public abstract int interpreter(Context context);
}

定义非终结表达式

//非终结表达式:加法
@Data
@AllArgsConstructor
public class Add extends AbstractExpression {

    private final AbstractExpression left;

    private final AbstractExpression right;

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

//非终结表达式:减法
@Data
@AllArgsConstructor
public class Subtract extends AbstractExpression {

    private final AbstractExpression left;

    private final AbstractExpression right;

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

//非终结表达式:乘法
@Data
@AllArgsConstructor
public class Multiply extends AbstractExpression {

    private final AbstractExpression left;

    private final AbstractExpression right;

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

//非终结表达式:除法
@Data
@AllArgsConstructor
public class Division extends AbstractExpression {

    private final AbstractExpression left;

    private final AbstractExpression right;

    @Override
    public int interpreter(Context context) {
        int right = this.right.interpreter(context);
        if (right != 0) {
            return left.interpreter(context) / right;
        }

        return -1;
    }
}

定义终结表达式

//终结表达式:变量
@Data
@AllArgsConstructor
public class Variable extends AbstractExpression {

    private final String key;

    @Override
    public int interpreter(Context context) {
        return context.getValue(key);
    }
}

定义上下文

//环境上下文
@Getter
public class Context {

    private final Map<String, Integer> valueMap = Maps.newHashMap();

    public void addValue(final String key, final int value) {
        valueMap.put(key, Integer.valueOf(value));
    }

    public int getValue(final String key) {
        return valueMap.get(key).intValue();
    }
}

测试:(a*b)/(a-b+c)

// (a*b)/(a-b+c)
public class Application {

    public static void main(String[] args) {
        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 multiplyValue = new Multiply(a, b);
        AbstractExpression subtractValue = new Subtract(a, b);
        AbstractExpression addValue = new Add(subtractValue, c);
        AbstractExpression divisionValue = new Division(multiplyValue, addValue);

        log.info("{}", context.getValueMap());
        log.info("(a*b)/(a-b+c) = {}", divisionValue.interpreter(context));
    }
}

结果

在这里插入图片描述
到此解释器模式的详解就到此结束了,谢谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值