1、定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中句子。
2、使用场景
音乐解释器,定义一套规则,O表示音阶 ‘O 1’表示低音阶,‘O 2’表示中音阶,‘O 3’表示高音阶;P表示休止符,‘C D E F G A B’ 表示’Do-Re-Mi-Fa-So-La-Ti’;音符长度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍,以此类推。
注意:所有字母和数字都要用半角空格分开,例如上海滩歌曲的第一句‘浪奔’,可以写成‘O 2 E 0.5 G 0.5 A 3’表示中音开始,演奏的是”Mi So La“。
3、代码结构UML图
演奏内容:包含解释器之外的一些全局信息。
表达式:抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点共享。
音符、音阶、音速:具体的表达式对象,实现于温服中的终结符相关联的解释操作。
4、类的实现
(1)、PlayContext (演奏内容类)
public class PlayContext {
//演奏文本
private String playText;
public String getPlayText() {
return playText;
}
public void setPlayText(String playText) {
this.playText = playText;
}
}
(2)、Expression (表达式类)
public abstract class Expression {
public void interpret(PlayContext context) {
if (context.getPlayText().length() == 0) {
return;
} else {
String playKey = context.getPlayText().substring(0, 1);
context.setPlayText(context.getPlayText().substring(2));
double playValue = Double.valueOf(context.getPlayText().substring(0, context.getPlayText().indexOf(" ")));
context.setPlayText(context.getPlayText().substring(context.getPlayText().indexOf(" ") + 1));
execute(playKey, playValue);
}
}
public abstract void execute(String key, double value);
}
(3)、Note(音符类)
public class Note extends Expression {
@Override
public void execute(String key, double value) {
String note = "";
switch (key) {
case "C":
note = "1";//表示如果获得的key是C则演奏1(Do),如果是D则演奏2'Re'
break;
case "D":
note = "2";
break;
case "E":
note = "3";
break;
case "F":
note = "4";
break;
case "G":
note = "5";
break;
case "A":
note = "6";
break;
case "B":
note = "7";
break;
}
System.out.println(note + " ");
}
}
(4)、Scale(音阶类)
public class Scale extends Expression {
@Override
public void execute(String key, double value) {
String scale = "";
switch ((int) value) {
case 1:
scale = "低音";
break;
case 2:
scale = "中音";
break;
case 3:
scale = "高音";
break;
}
System.out.println(scale + " ");
}
}
5、客户端调用
public static void main(String[] args) {
PlayContext context = new PlayContext();
System.out.println("上海滩:");
context.setPlayText("O 2 E 0.5 G 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 D 3 ");
Expression expression = null;
try {
while (context.getPlayText().length() > 0) {
String str = context.getPlayText().substring(0, 1);
switch (str) {
case "O":
//音阶
expression = new Scale();
break;
case "C":
case "D":
case "E":
case "F":
case "G":
case "A":
case "B":
case "P":
//音符
expression = new Note();
break;
}
expression.interpret(context);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
6、总结
如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。例如匹配 Email、电话号码,正则表达式等。
当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。
使用了解释器模式,意味着很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你 可以使用继承类改变或扩展该方法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写。
解释器也有不足的,解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。
参考:《大话设计模式》
来源:CSDN
作者:James-Tom
链接:https://blog.csdn.net/huangbin123/article/details/104372405