解释器模式:
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式解决的是—如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
其中的终结符表达式 和非终结符表达式可以理解为:公式R=R1+R2中,R1、R2为终结符表达式,+为非终结表达式(其后需要跟随一个终结符表达式)。
各个角色的代码----
AbstractExpression(抽象表达式),声明一个抽象的解释操作,这个接口作为抽象语法树中所有节点(即终结符表达式和非终结符表达式)所共享:
package com.design.interpreter;
public abstract class AbstractExpression {
public abstract void interpret(Context context);
}
TerminalExpression(终结符表达式)实现与文法中终结符相关联的解释操作,实现抽象表达式中所要求的接口,主要是一个interpret()方法。文法中的每一个终结符都有一个具体终结表达式与之相对应:
package com.design.interpreter;
public class TerminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
System.out.println("終結符解释器");
}
}
NonterminalExpression(非终结表达式)为文法中的非终结符实现解释操作,对文法中的每一条规则都需要一个具体的非终结表达式类,通过实现抽象表达式的interpret()方法实现解释操作,解释操作以递归的方式调用每条规则所代表符号的实例变量:
package com.design.interpreter;
public class NonterminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
System.out.println("非終結符解释器");
}
}
Context类(包含解释器之外的一些全局信息):
package com.design.interpreter;
public class Context {
private String input;
private String output;
Get&Set方法略…
}
客户端,构建表示该文法定义的语言中一个特定的句子抽象语法数,调用解释器操作:
package com.design.interpreter;
import java.util.ArrayList;
import java.util.List;
public class Test {
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 NonterminalExpression());
for (AbstractExpression abstractExpression : list) {
abstractExpression.interpret(context);
}
}
}
当有一个语言需要解释执行,并且你可以将改语言中的句子表示为一个抽象语法树时,可以使用解释器模式。
有了解释器模式,可以很容易的改变和拓展文法,因为该模式使用类来表示文法规则,可以使用继承来改变或者拓展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类大体相似,这些类都易于直接编写。
解释器模式的缺点:为文法中每一条规则至少定义了一个类,因为包含了许多规则的文法可能难于维护和管理,建议当文法十分复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。
以手机编辑铃声为例:
首先制定规则,S代表速度,500低速,1000中速,1500高速,O代表音阶,‘O 1’代表低音阶,‘O 2’代表中音阶,‘O 3’代表高音阶,‘P’代表休止符,‘CDEFGAB’代表音调,1表示一拍,0.5表示半拍,依此类推。所有的字母和数字使用空格分隔。例:“O 2 E 0.5 G 0.5 A 3 E 0.5”
演奏内容类Context:
package com.design.interpret;
public class Context {
//演奏文本
private String playText ;
public String getPlayText() {
return playText;
}
public void setPlayText(String playText) {
this.playText = playText;
}
}
表达式类AbstractExpression:
package com.design.interpret;
public abstract class AbstractExpression {
//将演奏文本解析为对应的key和value,根据key值指定解释器
public void interpret(Context context){
if(context.getPlayText().length()==0){
return;
}
//获取文本第一个字符作为key值
String playText = context.getPlayText();
String key = playText.substring(0,1);
//获取key值后截取文本
playText = playText.substring(2);
//获取截取后文本第一个字段作为value值
Double value = Double.parseDouble(playText.substring(0,playText.indexOf(" ")));
//获取value值后截取文本
playText = playText.substring(playText.indexOf(" ")+1);
context.setPlayText(playText);
//解释器执行
excute(key, value);
};
public abstract void excute(String key, Double value);
}
音符类NoteExpression:
package com.design.interpret;
public class NoteExpression extends AbstractExpression {
@Override
public void excute(String key, Double value) {
String note = "";
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+" ");
}
}
音调类ScaleExpression:
package com.design.interpret;
public class ScaleExpression extends AbstractExpression {
@Override
public void excute(String key, Double value) {
String scale = "";
switch (value.intValue()) {
case 1:
scale = "low";
break;
case 2:
scale = "middle";
break;
case 3:
scale = "high";
break;
}
System.out.print(scale+" ");
}
}
音速类SpeedExpression:
package com.design.interpret;
/**
* 音速类
* @author hydra
*
*/
public class SpeedExpression extends AbstractExpression {
@Override
public void excute(String key, Double value) {
String speed = "";
switch (value.intValue()) {
case 500:
speed = "slow";
break;
case 1000:
speed = "middle";
break;
case 1500:
speed = "fast";
break;
}
System.out.print(speed+" ");
}
}
因为解释器会不断重复使用,所以这里用到了享元模式来生成各种具体的解释器:
package com.design.interpret;
import java.util.Hashtable;
public class ExpressionFactory {
//使用hashtable变量储存编译器列表
private static Hashtable<Object, AbstractExpression> expressions = new Hashtable<Object, AbstractExpression>();
public static AbstractExpression createExpression(String text) {
String key = text.substring(0,1);
AbstractExpression expression = null;
switch (key) {
case "C":
case "D":
case "E":
case "F":
case "G":
case "A":
case "B":
expression = expressions.get("note");
if (expression == null) {
expression = new NoteExpression();
expressions.put("note", expression);
}
break;
case "O":
expression = expressions.get("scale");
if (expression == null) {
expression = new ScaleExpression();
expressions.put("scale", expression);
}
break;
case "S":
expression = expressions.get("speed");
if (expression == null) {
expression = new SpeedExpression();
expressions.put("speed", expression);
}
break;
}
//System.out.println(expressions.size());
return expression;
}
}
客户端演奏:
package com.design.interpret;
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
Context context = new Context() ;
//设置演奏文本
context.setPlayText("S 1500 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 E 0.5 D 3 ");
AbstractExpression expression = null;
try {
while (context.getPlayText().length()>0) {
//使用享元模式
expression = ExpressionFactory.createExpression(context.getPlayText());
expression.interpret(context);
}
} catch (Exception e) {
}
}
}
演奏结果:
以上。
共同学习,写下你的评论
评论加载中...
作者其他优质文章