友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

16. 解释器模式

16.1. 定义

根据 GoF 的著名著作 《设计模式》,解释器模式的定义如下:

解释器模式(Interpreter)

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来介绍语言中的句子。

— Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides
《设计模式》

16.2. 类图

Diagram

解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题[DP]。

因为这个匹配字符的需求在软件的很多地方都会使用,而且行为之间都非常类似,过去的做法是针对特定的需求,编写特定的函数,比如判断Email、匹配电话号码等等,与其为每一个特定需求都写一个算法函数,不如使用一种通用的搜索算法来解释执行一个正则表达式,该正则表达式定义了待匹配字符串的集合[DP]。而所谓的解释器模式,正则表达式就是它的一种应用,解释器为正则表达式定义了一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式。

AbstractExpression(抽象表达式),声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。

TerminalExpression(终结符表达式),实现与文法中的终结符相关联的解释操作。实现抽象表达式中所要求的接口,主要是一个interpret()方法。文法中每一个终结符都有一个具体终结表达式与之相对应。

NonterminalExpression(非终结符表达式),为文法中的非终结符实现解释操作。对文法中每一条规则R1、R2……Rn都需要一个具体的非终结符表达式类。通过实现抽象表达式的interpret()方法实现解释操作。解释操作以递归方式调用上面所提到的代表R1、R2……Rn中各个符号的实例变量。

Context,包含解释器之外的一些全局信息。

客户端代码,构建表示该文法定义的语言中一个特定的句子的抽象语法树。调用解释操作。

代码 98. interpreter/AbstractExpression.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package com.diguage.didp.interpreter;

/**
 * AbstractExpression 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:35
 */
public abstract class AbstractExpression {
  public abstract void interpret(Context context);
}
代码 99. interpreter/Client.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.diguage.didp.interpreter;

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

/**
 * Client 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:35
 */
public class Client {
  public static void main(String[] args) {
    Context context = new Context();
    List<AbstractExpression> expressions = new ArrayList<>();
    expressions.add(new TerminalExpression());
    expressions.add(new NonterminalExpression());
    expressions.add(new TerminalExpression());
    expressions.add(new TerminalExpression());

    expressions.forEach(e -> e.interpret(context));
  }
}
代码 100. interpreter/Context.java 类
 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
package com.diguage.didp.interpreter;

/**
 * Context 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:35
 */
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;
  }
}
代码 101. interpreter/NonterminalExpression.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.diguage.didp.interpreter;

/**
 * NonterminalExpression 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:35
 */
public class NonterminalExpression extends AbstractExpression {
  @Override
  public void interpret(Context context) {
    System.out.println("非终端解释器!");
  }
}
代码 102. interpreter/TerminalExpression.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.diguage.didp.interpreter;

/**
 * TerminalExpression 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:35
 */
public class TerminalExpression extends AbstractExpression {
  @Override
  public void interpret(Context context) {
    System.out.println("终端解释器!");
  }
}

16.3. 常见示例

  1. java.util.regex.Pattern

  2. java.text.Normalizer

  3. java.text.Format