大话设计模式笔记(二十四)の解释器模式

解释器模式

定义

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

目的

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

UML图

好处

容易改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。

不足

解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析或编译器生成器来处理。

举个栗子

实现一个简单的音乐解释器。规则大致有:“C D E F G A B”分别表示“Do-Re-Mi-Fa-So-La-Ti”;音符长度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍,以此类推。解释以下《上海滩》

Talk is cheap, show me the code

(屁话少说,放码过来)

 1.  /**
 2.   * 演奏内容类
 3.   * Created by callmeDevil on 2019/12/15.
 4.   */
 5.  public class PlayContext {
 6.  
 7.      // 演奏文本
 8.      private  String text;
 9.  
10.      // 省略 get set
11.  }
12.  
 1.  /**
 2.   * 表达式类
 3.   * Created by callmeDevil on 2019/12/15.
 4.   */
 5.  public abstract class Expression {
 6.  
 7.      // 解释器
 8.      public void interpret(PlayContext context){
 9.          if (context.getText().length() == 0) {
10.              return;
11.          } else {
12.              // 此方法用于将当前演奏文本第一条命令获得命令字母和其参数值
13.              // 例如:“O 3 E 0.5 G 0.5 A 3”,则 playKey 为O,而playValue 为3
14.              String playKey = context.getText().substring(0, 1);
15.              context.setText(context.getText().substring(2));
16.              double playValue = Double.parseDouble(context.getText().substring(0, context.getText().indexOf(" ")));
17.              // 获得playKey 和 playValue 后将其从演奏文本中移除
18.              // 例如:“O 3 E 0.5 G 0.5 A 3”变成了“E 0.5 G 0.5 A 3”
19.              context.setText(context.getText().substring(context.getText().indexOf(" ") + 1));
20.  
21.              excute(playKey, playValue);
22.          }
23.      }
24.  
25.      // 抽象方法执行,不同的文法的子类,有不同的执行处理
26.      public abstract void excute(String key ,double value);
27.  
28.  }
29.  
 1.  /**
 2.   * 音符类
 3.   * Created by callmeDevil on 2019/12/15.
 4.   */
 5.  public class Note extends Expression {
 6.      @Override
 7.      public void excute(String key, double value) {
 8.          String note = "";
 9.          switch (key) {
10.              case "C":
11.                  note = "1"; // 如果获得的 key 是C,则演奏1(do),是D则演奏2(Re),以此类推
12.                  break;
13.              case "D":
14.                  note = "2";
15.                  break;
16.              case "E":
17.                  note = "3";
18.                  break;
19.              case "F":
20.                  note = "4";
21.                  break;
22.              case "G":
23.                  note = "5";
24.                  break;
25.              case "A":
26.                  note = "6";
27.                  break;
28.              case "B":
29.                  note = "7";
30.                  break;
31.          }
32.          System.out.print(note + " ");
33.      }
34.  }
35.  
 1.  /**
 2.   * 音阶类
 3.   * Created by callmeDevil on 2019/12/15.
 4.   */
 5.  public class Scale extends Expression {
 6.      @Override
 7.      public void excute(String key, double value) {
 8.          String scale = "";
 9.          switch ((int) value) {
10.              case 1 :
11.                  scale = "低音";
12.                  break;
13.              case 2:
14.                  scale = "中音";
15.                  break;
16.              case 3:
17.                  scale = "高音";
18.                  break;
19.          }
20.          System.out.print(scale + " ");
21.      }
22.  }
23.  
 1.  public class Test {
 2.      public static void main(String[] args) {
 3.          PlayContext context = new PlayContext();
 4.          // 音乐-上海滩
 5.          System.out.println("上海滩:");
 6.          context.setText("O 2 E 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 ");
 7.          Expression expression = null;
 8.          try {
 9.              while (context.getText().length() > 0) {
10.                  String string = context.getText().substring(0, 1);
11.                  switch (string) {
12.                      case "O": // 当首字母是O时,表达式实例化为音阶
13.                          expression = new Scale();
14.                          break;
15.                      case "C":
16.                      case "D":
17.                      case "E":
18.                      case "F":
19.                      case "G":
20.                      case "A":
21.                      case "B":
22.                      case "P": // 当首字母是CDEFGAB以及休止符P时,则实例化为音符
23.                          expression = new Note();
24.                          break;
25.                  }
26.                  expression.interpret(context);
27.              }
28.          } catch (Exception e) {
29.              e.printStackTrace();
30.          }
31.      }
32.  }
33.  

运行结果

1.  上海滩:
2.  中音 3 6 3 5 2 3 5 6 高音 1 中音 6 5 1 3 2 
3.  

需求变更

增加一个文法,就是演奏速度,用“T”表示,毫秒为单位,‘T 1000’表示每节拍一秒。

增加一个子类

 1.  /**
 2.   * 音速类
 3.   * Created by callmeDevil on 2019/12/15.
 4.   */
 5.  public class Speed extends Expression{
 6.      @Override
 7.      public void excute(String key, double value) {
 8.          String speed;
 9.          if (value < 500) {
10.              speed = "快速";
11.          } else if (value >= 1000) {
12.              speed = "慢速";
13.          } else {
14.              speed = "中速";
15.          }
16.          System.out.print(speed + " ");
17.      }
18.  }
19.  

客户端改变

 1.  public class Test {
 2.      public static void main(String[] args) {
 3.          PlayContext context = new PlayContext();
 4.          // 音乐-上海滩
 5.          System.out.println("上海滩:");
 6.          // 增加速度的设置
 7.          context.setText("T 500 O 2 E 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3 ");
 8.          Expression expression = null;
 9.          try {
10.              while (context.getText().length() > 0) {
11.                  String string = context.getText().substring(0, 1);
12.                  switch (string) {
13.                      case "O": // 当首字母是O时,表达式实例化为音阶
14.                          expression = new Scale();
15.                          break;
16.                      case "T": // 增加对T的判断
17.                          expression = new Speed();
18.                          break;
19.                      case "C":
20.                      case "D":
21.                      case "E":
22.                      case "F":
23.                      case "G":
24.                      case "A":
25.                      case "B":
26.                      case "P": // 当首字母是CDEFGAB以及休止符P时,则实例化为音符
27.                          expression = new Note();
28.                          break;
29.                  }
30.                  expression.interpret(context);
31.              }
32.          } catch (Exception e) {
33.              e.printStackTrace();
34.          }
35.      }
36.  }
37.  

运行结果

1.  上海滩:
2.  中速 中音 3 6 3 5 2 3 5 6 高音 1 中音 6 5 1 3 2 
3.  
posted @   callmeDevil  阅读(426)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥
点击右上角即可分享
微信分享提示