解释器 Interpreter
解释器模式是一种行为设计模式,用于定义语言的语法^1规则表示,并提供解释器来处理句子中的语法。
解释器模式描述如何构建一个简单“语言”的语法解释器,通过更简洁的规则来表示复杂的逻辑。它的适用范围很小,只在一些非常特定的领域被用到(编译器、规则引擎、正则表达式、SQL
解析等)。
为什么要使用?
解释器模式的对象职责:
通过更简洁的规则来表示复杂的逻辑。
👉 将领域语言(即问题表征)定义为简单的语言语法。通过多个不同规则的简单组合来映射复杂的模型。
📜 例如,在开发中使用正则表达式来快速匹配 IP
地址,而不是将所有可能的情况都用 if-else
来进行编写。
👉 更便捷地提升解释数学公式这一类场景的计算效率。
📜 例如,需要通过一定的规则运算才能得出最后结果的情况,在使用解释器模式后,能够很好地通过预置地规则来进行判断和解释。
模式结构
- 抽象表达式(Abstract Expression)定义一个解释器有哪些操作,可以是抽象类或接口。同时说明只要继承或实现的子节点都需要实现这些操作方法。
- 终结符表达式(Terminal Expression)用于解释所有终结符^2的表达式。
- 非终结符表达式(Nonterminal Expression)用于解释所有非终结符^3表达式。
- 上下文(Context)包含解释器全局的信息。
- 请求者(Client)调用终结符表达式和非终结符表达式来推导语法树。
解释器模式的类图:
模式实现
该示例使用解释器模式实现“判断两个字符串中至少存在一个是输入字符串的子串(或)”和“判断两个字符串是否同时为输入字符串的子串(且)”。在非终结符表达式中做“且”或“或”的操作;在终结符表达式中判断“终结符字符串”是否是“输入字符串”的子串。
示例程序的类图
代码实现
抽象表达式
1 2 3 4 5 6 7 8 9
| public interface Expression {
boolean interpreter(String con); }
|
终结符表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class TerminalExpression implements Expression { private String data;
public TerminalExpression(String data) { this.data = data; }
@Override public boolean interpreter(String con) { if(con.contains(data)) { return true; } return false; } }
|
非终结符表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class OrExpression implements Expression { private Expression expr1; private Expression expr2;
public OrExpression(Expression expr1, Expression expr2) { this.expr1 = expr1; this.expr2 = expr2; }
@Override public boolean interpreter(String con) { return expr1.interpreter(con) || expr2.interpreter(con); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class AndExpression implements Expression { private Expression expr1; private Expression expr2;
public AndExpression(Expression expr1, Expression expr2) { this.expr1 = expr1; this.expr2 = expr2; }
@Override public boolean interpreter(String con) { return expr1.interpreter(con) && expr2.interpreter(con); } }
|
代码测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Test { public static void main(String[] args) { Expression mick = new TerminalExpression("mick"); TerminalExpression mia = new TerminalExpression("mia"); Expression isSingle = new OrExpression(mick, mia); Expression spike = new TerminalExpression("spike"); TerminalExpression mock = new TerminalExpression("mock"); Expression isCommitted = new AndExpression(spike, mock); System.out.println("'mick'是否包含'mick'或'mia':" + isSingle.interpreter("mick")); System.out.println("'mia'是否包含'mick'或'mia':" + isSingle.interpreter("mia")); System.out.println("'max'是否包含'mick'或'mia':" + isSingle.interpreter("max"));
System.out.println("'mock-spike'是否同时包含'spike'和'mock':" + isCommitted.interpreter("mock-spike")); System.out.println("'single-mock'是否同时包含'spike'和'mock':" + isCommitted.interpreter("single-mock")); } }
|
输出结果
1 2 3 4 5
| 'mick'是否包含'mick'或'mia':true 'mia'是否包含'mick'或'mia':true 'max'是否包含'mick'或'mia':false 'mock-spike'是否同时包含'spike'和'mock':true 'single-mock'是否同时包含'spike'和'mock':false
|
常用场景和解决方案
- 语言的语法较为简单并且对执行效率要求不高。
- 问题重复出现,且可以用一种简单的语言来进行表达。
- 一个语言需要解释执行。
模式的优缺点
优点 |
缺点 |
很容易改变和扩展语法逻辑。 |
维护成本很高。 |
更容易实现语法。 |
执行效率较低。 |
|
应用场景单一,复用性不高。 |
拓展知识
- 在解释器模式中通常会使用树的结构,终端表达式对象是叶对象,非终端表达式是组合对象。
- 解释器模式能够通过一些简短的规则来解决复杂的数据匹配问题。
🔙 设计模式
📌最后:希望本文能够给您提供帮助,文章中有不懂或不正确的地方,请在下方评论区💬留言!
🔗参考文献:
▶️ bilibili-趣学设计模式;黄靖锋. –拉勾教育
📖 图解设计模式 /(日)结城浩著;杨文轩译. –北京:人民邮电出版社,2017.1