设计模式-解释器模式

1、概述

行为型模式

解释器模式(Interpreter Pattern)指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子,属于行为型设计模式。

主要角色

抽象表达式(IExpression):负责定义一个解释方法 interpret,交由具体子类进行具体解释。
终结符表达式(TerminalExpression):实现文法中与终结符有关的解释操作。通常一个解释器中只有- 一个终结符表达式,但有多个实例,对应不同的终结符。
非终结符表达式(NonterminalExpression):实现文法中与非终结符有关的解释操作。
上下文环境类(Context):包含解释器之外的全局信息。它一般用来存放文法中各个终结符所对应的具体值。

2、优缺点

优点

可以通过继承等方式改变和扩展文法。每一个文法都可以表示为一个类,可以方便的实现一个语言。方便的增加新的解释表达式。

缺点

对于复杂的文法可能需要定义过多的解释类,难以维护。执行效率下,解释器模式中使用了大量的循环和递归调用,对于复杂的文法执行效率低。
文法比较简单。执行效率不是关键。一些重复出现的问题可以用一种简单的语言来表达。可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。

3、实现方式


import java.util.Stack;

//测试类
public class Test {
   public static void main(String[] args) {
      GPCalculator gpCalculator = new GPCalculator("2 + 3");
      System.out.println("2 + 3 = "+ gpCalculator.calculate());

      System.out.println("-------------");
      GPCalculator gpCalculator2 = new GPCalculator("2 * 3");
      System.out.println("2 * 3 = "+ gpCalculator2.calculate());

      System.out.println("-------------");
      GPCalculator gpCalculator3 = new GPCalculator("2 + 3 - 1");
      System.out.println("2 + 3 - 1 = "+ gpCalculator3.calculate());
   }

}

interface IArithmeticInterpreter {
   int interpret();
}

// 数字表达式
class NumberInterpreter implements IArithmeticInterpreter {
   private int value;

   public NumberInterpreter(int value) {
      this.value = value;
   }

   @Override
   public int interpret() {
      return this.value;
   }
}

abstract class Interpreter implements IArithmeticInterpreter {

   protected IArithmeticInterpreter left;
   protected IArithmeticInterpreter right;

   public Interpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
      this.left = left;
      this.right = right;
   }
}

class AddInterpreter extends Interpreter {
   public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
      super(left, right);
   }

   @Override
   public int interpret() {
      return this.left.interpret() + this.right.interpret();
   }
}

class SubInterpreter extends Interpreter {
   public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
      super(left, right);
   }

   @Override
   public int interpret() {
      return this.left.interpret() - this.right.interpret();
   }
}

class MultiInterpreter extends Interpreter {
   public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
      super(left, right);
   }

   @Override
   public int interpret() {
      return this.left.interpret() * this.right.interpret();
   }
}

class DivInterpreter extends Interpreter {
   public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
      super(left, right);
   }

   @Override
   public int interpret() {
      return this.left.interpret() / this.right.interpret();
   }
}


class GPCalculator {
   private Stack<IArithmeticInterpreter> stack = new Stack<>();

   public GPCalculator(String expression) {
      this.parse(expression);
   }

   /**
    * 解析表达式:约定表达式以空格分隔
    * 
    * @param expression
    */
   private void parse(String expression) {
      String[] elements = expression.split(" ");
      IArithmeticInterpreter left, right;

      for (int i = 0; i < elements.length; i++) {
         String operator = elements[i];
         if("+".equals(operator) || "-".equals(operator) || "*".equals(operator) || "/".equals(operator)){
            System.out.println("应用运算符:" + operator);
            left = this.stack.pop();
            right = new NumberInterpreter(Integer.valueOf(elements[++i]));
            System.out.println("出栈:left=" + left.interpret() + ", right=" + right.interpret());

            Interpreter interpreter = null;
            if("+".equals(operator)){
               interpreter = new AddInterpreter(left, right);
            }else if("-".equals(operator)){
               interpreter = new SubInterpreter(left, right);
            }else if("*".equals(operator)){
               interpreter = new MultiInterpreter(left, right);
            }else if("/".equals(operator)){
               interpreter = new DivInterpreter(left, right);
            }else{
               new RuntimeException("不支持该运算符:" + operator);
            }
            this.stack.push(interpreter);
            System.out.println("应用运算符计算结果入栈,result=" + interpreter.interpret());
         }else{
            NumberInterpreter numberInterpreter = new NumberInterpreter(Integer.valueOf(elements[i]));
            this.stack.push(numberInterpreter);
            System.out.println("入栈:" + numberInterpreter.interpret());
         }
      }
   }

   // 获取计算结果
   public int calculate() {
      return this.stack.pop().interpret();
   }

}

4、应用场景

1)一些重复出现的问题可以用一种简单的语言进行表达。

2)一个简单语法需要解释的场景。

3)逆波兰表达式

This entry was posted in 应用, 设计模式. Bookmark the permalink.