解释器模式
定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
解决
对于一些固定文法构建一个解释句子的解释器。
解释器模式(Interpreter)是一种针对特定问题设计的一种解决方案。例如,匹配字符串的时候,由于匹配条件非常灵活,使得通过代码来实现非常不灵活。
优点
- 能够很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。
- 比较容易实现文法,因为定义抽象语法树中各个节点地类的实现大体类似,这些类都易于直接编写。
缺点
- 解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。
- 易引起类膨胀。
- 可利用的场景较少。
- 解释器模式采用递归调用方法。
结构
解释器模式包含如下角色:
- AbstrExpression: 抽象表达式
- TerminalExpression: 终结符表达式
- NonterminalExpression: 非终结符表达式
- Context: 环境类:包含解释器之外的一些全局信息
实现
package interpreterpattern;
/**
* 声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享
*/
public abstract class AbstractExpression {
public abstract void interpret(Context context);
}
package interpreterpattern;
/**
* 实现与文法中的终结符相关联的解释操作,文法中每一个终结符都有一个具体终结表达式与之相对应
*/
public class TerminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
System.out.println("终端解释器");
}
}
package interpreterpattern;
/**
* 非终结符表达式,为文法中的非终结符实现解释操作。对文法中每一条规则R1、R2...Rn都需要一个具体的非终结符表达式类。
*/
public class NonTerminalExpression extends AbstractExpression{
@Override
public void interpret(Context context) {
System.out.println("非终端解释器");
}
}
package interpreterpattern;
/**
* 包含解释器之外的一些全局信息
*/
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;
}
}
package interpreterpattern;
import java.util.ArrayList;
import java.util.List;
/**
* 构建表示该文法定义的语言中一个特定的句子的抽象语法树,调用解释操作
*/
public class InterpreterClient {
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);
}
}
}
实例
做了一个正则化的小例子 该标准是 [单个数字-单个小写-单个大写]
package interpreterpattern.demo;
public abstract class AbstractExpression {
public abstract boolean interpret(String info);
}
package interpreterpattern.demo;
import java.util.HashSet;
import java.util.Set;
public class TerminalExpression extends AbstractExpression{
private Set<String> set =new HashSet<String>();
public TerminalExpression(String[] data)
{
for(int i=0; i<data.length;i++)
set.add(data[i]);
}
@Override
public boolean interpret(String info) {
if(set.contains(info))
{
return true;
}
return false;
}
}
package interpreterpattern.demo;
public class NonTerminalExpression extends AbstractExpression{
private AbstractExpression address=null;
private AbstractExpression name=null;
private AbstractExpression id=null;
public NonTerminalExpression(AbstractExpression address, AbstractExpression name, AbstractExpression id) {
this.address = address;
this.name = name;
this.id = id;
}
@Override
public boolean interpret(String info) {
String s[]=info.split("-");
return address.interpret(s[0])&&name.interpret(s[1])&&id.interpret(s[2]);
}
}
package interpreterpattern.demo;
public class Context {
private String[] shuzis={"1","2","3","4","5","6","7","8","9","0"};
private String[] xiaoxiezimus={"a","b","c","d","e","f","g","h","i","j","k","l"};
private String[] daxiezimus={"A","B","C","D","E","F","G"};
private AbstractExpression infomation;
public Context()
{
AbstractExpression shuzi=new TerminalExpression(shuzis);
AbstractExpression xiaoxiezimu=new TerminalExpression(xiaoxiezimus);
AbstractExpression daxiezimu=new TerminalExpression(daxiezimus);
infomation=new NonTerminalExpression(shuzi,xiaoxiezimu,daxiezimu);
}
public void jieshi(String info)
{
boolean ok=infomation.interpret(info);
if(ok) System.out.println("正确! ["+info+"] 满足 [单个数字-单个小写-单个大写] 的条件");
else System.out.println("错误! ["+info+"] 不满足 [单个数字-单个小写-单个大写] 的条件");
}
}
package interpreterpattern.demo;
public class InterpreterClient {
public static void main(String[] args) {
Context people=new Context();
people.jieshi("2-a-A");
people.jieshi("11-A-5");
people.jieshi("你-好-吖");
people.jieshi("2aA");
}
}