解释器模式:给定一个语言,定义它的文法的一种表示。并定义一个解释器,这个解释器使用该表示来解释
语言中的句子。
1.如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。
这样就可以构造一个解释器,该解释器通过解释这些句子来解决该问题。
2.当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。
3.使用解释器模式时,可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,
可使用继承来改变或扩展该文法。 也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,
这些类都易于直接编写。
4.抽象语法树的每一个节点都代表一个语句,而在每个节点上都可以执行解释方法。这个解释方法的
执行就代表这个语句被解释。
5.一般系统中很多类使用相似的语法,可以使用一个解释器来代替为每一个规则实现一个解释器。
6.不足:解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。
建议当文法非常复杂时,使用其它的技术如语法分析程序或编译器生成器来处理。
/**
* 抽象表达式,声明一个抽象的解释操作,这个接口为抽象语法树中的所有节点所共享。
*/
public abstract class AbstractExpression {
public abstract void interpret(Context context);
}
/**
* 终结符表达式,实现与文法中的终结符相关联的解释操作。
* 文法中每一个终结符都有一个具体的终结表达式与之相对应。
*/
public class TerminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
System.out.println("终端解释器");
}
}
/**
* 非终结符表达式,为文法中的非终结符实现解释操作。
* 对文法中的每一条规则R1,R2...Rn都需要一个具体的非终结符表达式类。
* 解释操作以递归方式调用上面所提到的代表R1,R2....Rn中的各个符号的实例变量。
*/
public class NonTerminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
System.out.println("非终端解释器");
}
}
/**
* 包含解释器之外的一些全局信息。
*/
public class Context {
private String intput;
private String output;
public String getIntput() {
return intput;
}
public void setIntput(String intput) {
this.intput = intput;
}
public String getOutput() {
return output;
}
public void setOutput(String output) {
this.output = output;
}
}
public class Main {
public static void main(String[] args) {
// 构建表示该文法定义的语言中一个特定的句子的抽象语法树,调用解释操作。
Context context = new Context();
List<AbstractExpression> list = new ArrayList<AbstractExpression>();
list.add(new TerminalExpression());
list.add(new NonTerminalExpression());
list.add(new TerminalExpression());
list.add(new TerminalExpression());
for(AbstractExpression expression:list){
expression.interpret(context);
}
}
}
解释器模式示例:音乐解释器事例(音符,音阶,音速等)
/**
* 演奏内容类
*/
public class PlayContext {
// 演奏文本
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
/**
* 表达式类
*/
public abstract class Expression {
//解释器
public void interpret(PlayContext context){
if(context.getText().length()==0){
return;
}else{
// 获取playKey和playValue
//(例:"O 3 E 0.5 G 0.5 A 3 "playKey为O,playValue为3)
char playKey = context.getText().substring(0,1).charAt(0);
context.setText(context.getText().substring(2));
Double playValue = Double.parseDouble(context.getText()
.substring(0,context.getText().indexOf(" ")));
// 获得playKey和playValue后,将其从演奏文本中移除
// (例:"O 3 E 0.5 G 0.5 A 3 "变成"E 0.5 G 0.5 A 3 ")
context.setText(context.getText().substring(context.getText().indexOf(" ")+1));
execute(playKey, playValue);
}
}
// 执行,抽象方法执行不同的文法子类,有不同的执行处理。
public abstract void execute(char key,Double value);
}
/**
* 音符类,终结符表达式
*/
public class Note extends Expression{
@Override
public void execute(char key, Double value) {
String note = "";
// 如果获得的key是C则演奏1(do),D则演奏2(Re)
switch(key){
case 'C':
note = "1";
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.print(note+" ");
}
}
/**
* 音阶类,终结符表达式
*/
public class Scale extends Expression{
@Override
public void execute(char key, Double value) {
String scale = "";
// 如果获得的key是O并且value是1则演奏低音,2则是中音,3则是高音
switch(value.intValue()){
case 1:
scale = "低音";
break;
case 2:
scale = "中音";
break;
case 3:
scale = "高音";
break;
}
System.out.print(scale+" ");
}
}
/**
* 音速类,终结符表达式
*/
public class Speed extends Expression{
@Override
public void execute(char key, Double value) {
// T 1000 表示每节拍一秒,T 500 表示每节拍半秒
String speed = "";
if(value<500){
speed = "快速";
}else if(value>=1000){
speed = "慢速";
}else{
speed = "中速";
}
System.out.print(speed+" ");
}
}
public class Main {
public static void main(String[] args) {
PlayContext context = new PlayContext();
System.out.println("上海滩:");
context.setText("T 500 O 2 E 0.5 G 0.5 A 3 E 0.5 G 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");
Expression expression = null;
try{
while (context.getText().length()>0){
char str = context.getText().substring(0,1).charAt(0);
switch (str){
case 'O':
// 当首字母是O时,表达式实例化为音阶
expression = new Scale();
break;
case 'T':
// 当首字母是T时,表达式实例化为音速
expression = new Speed();
break;
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'A':
case 'B':
case 'P':
// 当首字母是CDEFGAB以及休止符P时,表达式实例化为音符
expression = new Note();
break;
}
expression.interpret(context);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
输出结果如下:
上海滩:
中速 中音 3 5 6 3 5 5 2 3 5 6 高音 1 中音 6 5 1 3