[工作中的设计模式]解释器模式模式Interpreter

一、模式解析

  解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。

以上是解释器模式的类图,事实上我很少附上类图,但解释器模式确实比较抽象,为了便于理解还是放了上来,此模式的要点是:

1、客户端提供一个文本、表达式或者其他,约定解析格式

2、针对文本中可以分为终结符表达式非终结符表达式

3、终结符表达式无需进一步解析,但仍需要转化为抽象接口的实例

4、针对非终结表达式,没一种标示需要定义一种解析类,如果后续有扩展,则进一步扩展一种解析类,并修改解析分支即可完成扩展

二、模式代码

1、定义整体环境类,保存除了解析器外,其他全局信息

package interpreter.patten;

public class Context {
    private String input;
    private String output;
    public String getInput() {
        return input;
    }
    public void setInput(String input) {
        this.input = input;
    }
    public String getOutput() {
        return output;
    }
    public void setOutput(String output) {
        this.output = output;
    }
}

2、定义抽象解析器

package interpreter.patten;

public abstract class AbstractExpression {
    public abstract void interpret(Context context);
}

3、定义终结符解析器

package interpreter.patten;

public class TerminalExpression extends AbstractExpression {

    @Override
    public void interpret(Context context) {
        System.out.println("终结符解析器");
    }
}

4、定义非终结符表达式

package interpreter.patten;

public class UnTerminalExpression extends AbstractExpression {

    @Override
    public void interpret(Context context) {
        System.out.println("非终结符解析器");
    }
}

5、定义客户端类

package interpreter.patten;

import java.util.ArrayList;
import java.util.List;

public class Client {
    public static void main(String[] args) {
        Context context=new Context();
        List<AbstractExpression> list=new ArrayList<AbstractExpression>();
        list.add(new TerminalExpression());
        list.add(new UnTerminalExpression());
        list.add(new TerminalExpression());
        list.add(new UnTerminalExpression());
        list.add(new TerminalExpression());
        list.add(new UnTerminalExpression());
        for(AbstractExpression expression:list){
            expression.interpret(context);
        }
    }
}

6、客户端执行结果

终结符解析器
非终结符解析器
终结符解析器
非终结符解析器
终结符解析器
非终结符解析器

三、应用场景

以上模式代码完整的实现了类图中的所有内容,并打印出了结果,但是又显得毫无意义,看起来比较蠢,这是因为在我们的实际使用中解释器模式使用非常稀少,他只有在做特定公式的解析或者语言解析才会用到,很不幸,目前我的工作中似乎没有可以完整的展示此模式的例子,但是为了加深印象,我们采用《java与模式》中的例子进行说明

此为java与模式中提供的相关例子,主要用于解析条件判断语句,例如:A and B,A or B ,not A等条件语句,表达式分为几类

1、终结符表达式-常量表达式,主要显示true或者false

2、终结符表达式=-变量表达式,主要是需要判断的条件

3、非终结符表达式-各种运算符,包括:与或非

四、场景代码

1、环境(Context)类定义出从变量到布尔值的一个映射

package interpreter.example;

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

public class Context {

    private Map<Variable,Boolean> map = new HashMap<Variable,Boolean>();
    
    public void assign(Variable var , boolean value){
        map.put(var, new Boolean(value));
    }
    
    public boolean lookup(Variable var) throws IllegalArgumentException{
        Boolean value = map.get(var);
        if(value == null){
            throw new IllegalArgumentException();
        }
        return value.booleanValue();
    }
}

2、定义抽象表达式

package interpreter.example;
public abstract class Expression {
    /**
     * 以环境为准,本方法解释给定的任何一个表达式
     */
    public abstract boolean interpret(Context ctx);
    /**
     * 检验两个表达式在结构上是否相同
     */
    public abstract boolean equals(Object obj);
    /**
     * 返回表达式的hash code
     */
    public abstract int hashCode();
    /**
     * 将表达式转换成字符串
     */
    public abstract String toString();
}

3、定义常量表达式

package interpreter.example;
public class Constant extends Expression{
    
    private boolean value;

    public Constant(boolean value){
        this.value = value;
    }
    
    @Override
    public boolean equals(Object obj) {
        
        if(obj != null && obj instanceof Constant){
            return this.value == ((Constant)obj).value;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        
        return value;
    }

    @Override
    public String toString() {
        return new Boolean(value).toString();
    }
    
}

4、定义变量表达式

package interpreter.example;
public class Variable extends Expression {

    private String name;

    public Variable(String name){
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {
        
        if(obj != null && obj instanceof Variable)
        {
            return this.name.equals(
                    ((Variable)obj).name);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public boolean interpret(Context ctx) {
        return ctx.lookup(this);
    }

}

5、定义逻辑与

package interpreter.example;
public class And extends Expression {

    private Expression left,right;
    
    public And(Expression left , Expression right){
        this.left = left;
        this.right = right;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof And)
        {
            return left.equals(((And)obj).left) &&
                right.equals(((And)obj).right);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        
        return left.interpret(ctx) && right.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " AND " + right.toString() + ")";
    }

}

6、定义逻辑或

package interpreter.example;
public class Or extends Expression {
    private Expression left,right;

    public Or(Expression left , Expression right){
        this.left = left;
        this.right = right;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof Or)
        {
            return this.left.equals(((Or)obj).left) && this.right.equals(((Or)obj).right);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return left.interpret(ctx) || right.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " OR " + right.toString() + ")";
    }

}

7、定义逻辑非

package interpreter.example;
public class Not extends Expression {

    private Expression exp;
    
    public Not(Expression exp){
        this.exp = exp;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj != null && obj instanceof Not)
        {
            return exp.equals(
                    ((Not)obj).exp);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return this.toString().hashCode();
    }

    @Override
    public boolean interpret(Context ctx) {
        return !exp.interpret(ctx);
    }

    @Override
    public String toString() {
        return "(Not " + exp.toString() + ")";
    }

}

8、定义客户端代码

package interpreter.example;
public class Client {

    public static void main(String[] args) {
        Context ctx = new Context();
        Variable x = new Variable("x");
        Variable y = new Variable("y");
        Constant c = new Constant(true);
        ctx.assign(x, false);
        ctx.assign(y, true);
        
        Expression exp = new Or(new And(c,x) , new And(y,new Not(x)));
        System.out.println("x=" + x.interpret(ctx));
        System.out.println("y=" + y.interpret(ctx));
        System.out.println(exp.toString() + "=" + exp.interpret(ctx));
    }

}

五、总结

解释器模式可以很容易改变和扩展解释方法,但是由于每个文本都需要定义一个类,会导致后期很难管理,因此不太常用。

注:此文代码和案例都是一些经典实现,并无工作体验,以后如果有具体案例再替换

posted @ 2016-02-15 23:00  孤子  阅读(312)  评论(0编辑  收藏  举报