Fork me on GitHub

设计模式-解释器模式(26)

定义

解释器模式(Interpreter Pattern)是一种按照规定语法对表达式进行解析的方案,在项目中较少使用。

英文:Given a language,define a representation for its grammer along with an interpreter that uses the representation to interpret that uses the representation to interpret sentences in the language.

 翻译:给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示方法来解释语言中的句子。

角色

抽象表达式(Abstract Expression)角色:该角色声明一个所有的具体表达式角色都需要实现的抽象接口,该接口主要是含有一个解释操作interpreter()操作。

终结符表达式(Terminal Expression)角色:该角色实现了抽象表达式角色所要求的接口,文法中的每一个终结符都会有一个具体终结表达式与之相对应。

非终结符表达式(Nonterminal Expression)角色:该角色是一个具体角色,文法中的每一条规则都对应一个非终结符表达式类。

环境角色(Context)角色:该角色提供解释器之外的全局信息。

客户端(Client)角色:该角色创建一个抽象语法树,调用解释操作方法。

/**
 * 抽象表达式.
 */
public abstract class AbstractExpression {
    //每个表达式必须有一个解析任务
    public abstract Object interpreter();
}

/**
 * 终结符表达式
 */
public class TerminalExpression extends AbstractExpression {
    //通常终结符表达式只有一个,但是有多个对象
    @Override
    public Object interpreter() {
        return null;
    }
}

/**
 * 非终结符表达式
 */
public class NonterminalExpression extends AbstractExpression {
    //每个非终结符表达式都会对其他表达式产生依赖
    public NonterminalExpression(AbstractExpression expression) {
    }

    @Override
    public Object interpreter() {
        //进行文法处理
        return null;
    }
}

/**
 * 环境角色
 */
public class Context {
    private HashMap map = new HashMap();     //用来容纳所有表达式
}

//通常Client是一个封装类,封装的过程就是传递进来一个规范语法文件,解释器分析后产生结果并返回,避免调用者与语法解释器的耦合关系
public class Client { Context context = new Context(); public static void main(String[] args) { for(;;){ //进行语法判断,并产生递归调用 } } }

源码

优点

  • 简单的语法分析工具。
  • 扩展性良好,若修改语法规则,只要修改相应的非终结符表达式即可,若扩展语法,只要增加非终结符类即可。

缺点

  • 解释器模式会引起类膨胀。每个语法都要产生一个非终结符表达式,语法比较复杂时就可能产生大量的类文件,不易维护。
  • 采用递归调动方法。每个非终结符表达式只关心与自己有关的表达式,每个表达式想要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下才使用的,它使程序不易调试且影响效率。

使用场景

  • 重复发生的问题可以使用解释器模式。例如:多个应用服务器,每天产生大量的日志,系统需要对日志文件进行分析处理,由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相同的,非终结符表达式就需要制定。
  • 一个简单语法需要解释的场景。
/**
 * 抽象解释器
 */
public interface ArithmeticExpression {
    int interpret(Variables variables);
}

/**
 * 算数表达式中的变量--终结符角色
 */
public class Variable implements ArithmeticExpression {
    @Override
    public int interpret(Variables variables) {
        return variables.get(this);
    }
}

/**
 * 加算法--非终结符角色
 */
public class Plus implements ArithmeticExpression {
    ArithmeticExpression left;    //终结符角色
    ArithmeticExpression right;     //终结符角色

    public Plus(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;
    }

    /**
     * 操作终结符角色
     * @param variables
     * @return
     */
    @Override
    public int interpret(Variables variables) {
        //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值
        return left.interpret(variables)+right.interpret(variables);
    }
}

/**
 * 减法--非终结符角色
 */
public class Substract implements ArithmeticExpression{
    ArithmeticExpression left;    //终结符角色
    ArithmeticExpression right;    //终结符角色

    public Substract(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Variables variables) {
        //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值
        return left.interpret(variables)-right.interpret(variables);
    }
}

/**
 * 乘算法--非终结符角色
 */
public class Multiply implements ArithmeticExpression {
    ArithmeticExpression left;      //终结符角色
    ArithmeticExpression right;     //终结符角色

    public Multiply(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Variables variables) {
        //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值
        return left.interpret(variables)*right.interpret(variables);
    }
}

/**
 * 除算法--非终结符角色
 */
public class Division implements ArithmeticExpression {
    ArithmeticExpression left;      //终结符角色
    ArithmeticExpression right;     //终结符角色

    public Division(ArithmeticExpression left, ArithmeticExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Variables variables) {
        //终结符角色.interpret(环境角色)-->环境角色.get(this)获取终结符角色在环境角色中注册的值
        return left.interpret(variables)/right.interpret(variables);
    }
}

/**
 * 环境角色--使用Map存储各个变量的值
 */
public class Variables {
    //key为变量类型,value为变量值.Variable为封装int的包装类
    Map<Variable,Integer> v = new HashMap<Variable,Integer>();
    //封装值,将终结符及其对应的解释封装到环境角色
    public void put(Variable variable,int value){
        v.put(variable,value);
    }
    //取值,从环境角色中取出非终结符对应的值
    public int get(Variable variable){
        return v.get(variable);
    }
}

public class Main {
    public static void main(String[] args) {
        Variables v = new Variables();    //环境角色
        //终结符
        Variable x = new Variable();
        Variable y = new Variable();
        Variable z = new Variable();
        //将终结符注册到环境中
        v.put(x,10);
        v.put(y,20);
        v.put(z,30);

        //计算x*(y+z/x)-x
        //非终结符接口 = new 非终结符(终结符,终结符),将两个终结符注册到非终结符中操作
        ArithmeticExpression e = new Substract(new Multiply(x,new Plus(y,new Division(z,x))),x);
        //解析非终结符接口 => 非终结符成员变量(终结符)相互操作 => 终结符.interpret(环境角色)  =>  环境角色.get(this)获取终结符代表的值,拿这些值进行操作
        int result = e.interpret(v);
        System.out.println(result);

    }
}    

源码

个人总结

终结符实现抽象表达式的接口,interpert(环境角色)解析自身代表的value。

非终结符实现抽象表达式接口,interpert(环境角色)解析终结符代表的的value相互操作的结果。

posted @ 2018-04-27 15:19  秋夜雨巷  阅读(264)  评论(0编辑  收藏  举报