bboyjing's blog

HeadFirst设计模式二十【解释器模式】

解释器模式可以用来为语言创建解释器,也就是说可以再创造出一门语言。

场景描述

为了说明解释器模式的实现方式,给出一个最简单的文法和对应的解释器模式的实现,就是模拟Java语言中对布尔表达式进行操作和求值。比如说,给定一个表达式:(true AND x) OR (y AND (NOT x)),求该表达式的值是true还是false。这个语言简单的文法如下:

1
2
3
4
5
6
Expression := Constant | Variable | Or | And | Not
And := Expression 'And' Expression
Or := Expression 'Or' Expression
Not := Expression 'Not' Expression
Variable := 任何标识符
Constant := 'true' | 'false'

文法中涉及到的名词,在代码实现部分均会有对应的类,下面就来看一下如何实现。

代码实现

  1. Expression抽象,Context类是整个运行环境的上下文,该类稍候给出。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public abstract class Expression {
    /**
    * 解释给定的任意表达式
    */
    public abstract boolean interpret(Context ctx);
    /**
    * 检验两个表达式在结构上是否相同
    */
    @Override
    public abstract boolean equals(Object o);
    /**
    * 返回表达式的HashCode
    */
    @Override
    public abstract int hashCode();
    /**
    * 将表达式转换成字符串
    */
    @Override
    public abstract String toString();
    }
  2. Variable类用于创建一个有名字的变量,比如new Variable("x"),所以该类给出了一个成员变量name

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    public class Variable extends Expression {
    private String name;
    public Variable(String name) {
    this.name = name;
    }
    /**
    * 解释操作
    * 从Context中找出变量对应的value值
    */
    @Override
    public boolean interpret(Context ctx) {
    return ctx.lookup(this);
    }
    /**
    * 检验两个表达式在结构上是否相同
    */
    @Override
    public boolean equals(Object o) {
    if (o instanceof Variable) {
    return this.name.equals(((Variable) o).name);
    }
    return false;
    }
    /**
    * 返回表达式的HashCode
    */
    @Override
    public int hashCode() {
    return (this.toString()).hashCode();
    }
    /**
    * 将表达式转换成字符串
    */
    @Override
    public String toString() {
    return name;
    }
    }
  3. 实现Context类,该类用于保存上下文,其实就是运行环境中所有变量对应的布尔值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Context {
    private HashMap map = new HashMap();
    /**
    * 给变量赋值
    */
    public void assign(Variable var, boolean value) {
    map.put(var, value);
    }
    /**
    * 查找变量的值
    */
    public boolean lookup(Variable var) {
    Boolean value = (Boolean) map.get(var);
    if (value == null) {
    throw new IllegalArgumentException();
    }
    return value;
    }
    }
  4. 实现Constant类,因为是常量,所以该类的解释方法直接返回成员变量value的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class Constant extends Expression {
    private boolean value;
    public Constant(boolean value) {
    this.value = value;
    }
    @Override
    public boolean interpret(Context ctx) {
    return value;
    }
    @Override
    public boolean equals(Object o) {
    if (o instanceof Constant) {
    return this.value == ((Constant) o).value;
    }
    return false;
    }
    @Override
    public int hashCode() {
    return (this.toString()).hashCode();
    }
    @Override
    public String toString() {
    return Boolean.toString(value);
    }
    }
  5. 实现And操作,作用是由两个布尔表达式通过逻辑与操作给出一个新的布尔表达式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public class And extends Expression {
    private Expression left, right;
    public And(Expression left, Expression right) {
    this.left = left;
    this.right = right;
    }
    /**
    * 左表达式和右表达式分别解释操作之后再作&&操作
    */
    @Override
    public boolean interpret(Context ctx) {
    return left.interpret(ctx) && right.interpret(ctx);
    }
    @Override
    public boolean equals(Object o) {
    if (o instanceof And) {
    return this.left.equals(((And) o).left) && this.right.equals(((And) o).right);
    }
    return false;
    }
    @Override
    public int hashCode() {
    return (this.toString()).hashCode();
    }
    @Override
    public String toString() {
    return "(" + left.toString() + " AND " + right.toString() + ")";
    }
    }
  6. 实现Or操作,作用是由两个布尔表达式通过逻辑或操作给出一个新的布尔表达式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class Or extends Expression {
    private Expression left, right;
    public Or(Expression left, Expression right) {
    this.left = left;
    this.right = right;
    }
    @Override
    public boolean interpret(Context ctx) {
    return left.interpret(ctx) || right.interpret(ctx);
    }
    @Override
    public boolean equals(Object o) {
    if (o instanceof Or) {
    return this.left.equals(((Or) o).left) && this.right.equals(((Or) o).right);
    }
    return false;
    }
    @Override
    public int hashCode() {
    return (this.toString()).hashCode();
    }
    @Override
    public String toString() {
    return "(" + left.toString() + " OR " + right.toString() + ")";
    }
    }
  7. 实现Not操作,作用是由一个布尔表达式通过逻辑非操作给出一个新的布尔表达式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class Not extends Expression {
    private Expression exp;
    public Not(Expression exp) {
    this.exp = exp;
    }
    @Override
    public boolean interpret(Context ctx) {
    return !exp.interpret(ctx);
    }
    @Override
    public boolean equals(Object o) {
    if (o instanceof Not) {
    return this.exp.equals(((Not) o).exp);
    }
    return false;
    }
    @Override
    public int hashCode() {
    return this.toString().hashCode();
    }
    @Override
    public String toString() {
    return "(Not " + exp.toString() + ")";
    }
    }
  8. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class Test {
    public static void main(String[] args) {
    // 声明Context
    Context ctx = new Context();
    // 声明x、y两个变量,并且存储到Context上下文中
    Variable x = new Variable("x");
    Variable y = new Variable("y");
    ctx.assign(x, false);
    ctx.assign(y, true);
    // 声明一个常量
    Constant c = new Constant(true);
    // 声明测试表达式:(true AND x) OR (y AND (NOT x))
    Expression exp = new Or(new And(c, x), new And(y, new Not(x)));
    // 解释声明的x、y变量并输出
    System.out.println("x = " + x.interpret(ctx));
    System.out.println("y = " + y.interpret(ctx));
    // 解释表达式并输出
    System.out.println(exp.toString() + " = " + exp.interpret(ctx));
    }
    }

个人感觉这个模式特别的地方是,Context中存储了表达式中用到的所有变量,并且头从到尾传递该对象;另外一点特别的是interpret方法的调用有点递归的意思。本章节就学到这里了。