该项目源码地址:https://github.com/ggb2312/Code/tree/master/java-basic/design-pattern
(设计模式相关代码与笔记)
1. 定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。(为了解释一种语言,而为语言创建的解释器)
2. 适用场景
某个特定类型问题发生频率足够高
3. 类图与角色
AbstractExpression: 抽象表达式。声明一个抽象的解释操作,该接口为抽象语法树中所有的节点共享。
TerminalExpression: 终结符表达式。实现与文法中的终结符相关的解释操作。实现抽象表达式中所要求的方法。文法中每一个终结符都有一个具体的终结表达式与之相对应。
NonterminalExpression: 非终结符表达式。为文法中的非终结符相关的解释操作。
Context: 环境类。包含解释器之外的一些全局信息。
Client: 客户类。
抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 在解释器模式中由于每一种终结符表达式、非终结符表达式都会有一个具体的实例与之相对应,所以系统的扩展性比较好。
4. 相关设计模式
解释器模式与适配器模式
适配器模式是不知道预先要适配的规则,解释器模式要先把规则写好,根据规则解释。
5. 模式实例
背景:现在我们用解释器模式来实现一个基本的加、减、乘、除和求模运算。例如用户输入表达式“3 * 4 / 2 % 4”,输出结果为2。下图为该实例的UML结构图:
抽象语法树
抽象表达式:Node
public interface Node {
public int interpret();
}
非终结表达式:ValueNode 主要用解释该表达式的值。
public class ValueNode implements Node
{
private int value;
public ValueNode(int value)
{
this.value=value;
}
@Override
public int interpret()
{
return this.value;
}
}
终结表达式抽象类,由于该终结表达式需要解释多个运算符号,同时用来构建抽象语法树:
public abstract class SymbolNode implements Node {
protected Node left;
protected Node right;
public SymbolNode(Node left, Node right) {
this.left = left;
this.right = right;
}
}
MulNode
public class MulNode extends SymbolNode {
public MulNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return left.interpret() * right.interpret();
}
}
ModNode
package com.desgin.pattern.behavioral.interpreter;
public class ModNode extends SymbolNode {
public ModNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return super.left.interpret() % super.right.interpret();
}
}
DivNode
public class DivNode extends SymbolNode {
public DivNode(Node left, Node right) {
super(left, right);
}
@Override
public int interpret() {
return super.left.interpret() / super.right.interpret();
}
}
Calculator
import java.util.Stack;
public class Calculator {
private String statement;
private Node node;
public void build(String statement) {
Node left = null, right = null;
Stack stack = new Stack();
String[] statementArr = statement.split(" ");
for (int i = 0; i < statementArr.length; i++) {
if (statementArr[i].equalsIgnoreCase("*")) {
left = (Node) stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new MulNode(left, right));
} else if (statementArr[i].equalsIgnoreCase("/")) {
left = (Node) stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new DivNode(left, right));
} else if (statementArr[i].equalsIgnoreCase("%")) {
left = (Node) stack.pop();
int val = Integer.parseInt(statementArr[++i]);
right = new ValueNode(val);
stack.push(new ModNode(left, right));
} else {
stack.push(new ValueNode(Integer.parseInt(statementArr[i])));
}
}
this.node = (Node) stack.pop();
}
public int compute() {
return node.interpret();
}
}
客户端:Client
public class Client {
public static void main(String args[]) {
String statement = "3 * 2 * 4 / 6 % 5";
Calculator calculator = new Calculator();
calculator.build(statement);
int result = calculator.compute();
System.out.println(statement + " = " + result);
}
}
测试结果:
6. 优缺点
优点:
- 语法由很多类表示,容易改变及扩展此”语言”
缺点:
- 当语法规则数目太多时,增加了系统复杂度
执行效率比较低,可利用场景比较少。
7. 扩展-JDK1.7源码以及框架中的解释器模式
java.util.regex.Pattern正则解释器,相当于是一个语法。
Spring中的解释器
package com.desgin.pattern.behavioral.interpreter.springel;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* Create by lastwhisper on 2019/2/10
*/
public class SpringTest {
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("100 * 2 + 400 * 1 + 66");
int value = (int) expression.getValue();
System.out.println(value);
}
}
参考
https://www.cnblogs.com/chenssy/p/3346427.html