解释器模式
解释器模式介绍
定义
给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。 用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
优点
- 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
- 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。
缺点
- 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
- 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
- 可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。
应用场景
- 当语言的文法较为简单,且执行效率不是关键问题时。
- 当问题重复出现,且可以用一种简单的语言来进行表达时。
- 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。
注意:解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。如果碰到对表达式的解释,在 Java 中可以用 Expression4J 或 Jep 等来设计。
解释器模式
结构
- 抽象表达式(Abstract Expression)角色:
定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。 - 终结符表达式(Terminal Expression)角色:
是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。 - 非终结符表达式(Nonterminal Expression)角色:
也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。 - 环境(Context)角色:
通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。 - 客户端(Client):
主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

模板实现 判断文法
抽象终结符:某个具体的判断
具体终结符:是否为男性,是否有工作
抽象非终结符:连接逻辑
具体终结符:且,或

import com.sun.istack.internal.NotNull;
import java.util.HashMap;
import java.util.LinkedList;
/**
* 抽象表达式类
*/
interface AbstractExpression {
/**
* 解释方法
*
* @param context 被解释的内容
* @return 当前处理后的字符串
*/
boolean interpret(Context context);
}
/**
* 终结符表达式抽象类
*/
abstract class TerminalExpression implements AbstractExpression {
protected final String str;
public TerminalExpression(String str) {
this.str = str;
}
}
class IsMaleExpression extends TerminalExpression {
public IsMaleExpression(String str) {
super(str);
}
@Override
public boolean interpret(Context context) {
boolean res = context.getSex(super.str);
System.out.println(super.str + "性别为" + (res ? "男" : "女"));
return res;
}
}
class HasJobExpression extends TerminalExpression {
public HasJobExpression(String str) {
super(str);
}
@Override
public boolean interpret(Context context) {
String job = context.getJob(super.str);
if (job == null || job.isEmpty()) {
System.out.println(super.str + "没有工作");
return false;
} else {
System.out.println(super.str + "有工作,工作为:" + job);
return true;
}
}
}
/**
* 非终结符表达式抽象类
*/
abstract class NonterminalExpression implements AbstractExpression {
protected final AbstractExpression left;
protected final AbstractExpression right;
public NonterminalExpression(AbstractExpression left, AbstractExpression right) {
this.left = left;
this.right = right;
}
}
class AndExpression extends NonterminalExpression {
public AndExpression(AbstractExpression left, AbstractExpression right) {
super(left, right);
}
@Override
public boolean interpret(Context context) {
return super.left.interpret(context) && super.right.interpret(context);
}
}
class OrExpression extends NonterminalExpression {
public OrExpression(AbstractExpression left, AbstractExpression right) {
super(left, right);
}
@Override
public boolean interpret(Context context) {
return super.left.interpret(context) || super.right.interpret(context);
}
}
/**
* 环境类:全局文本信息
*/
class Context {
private final HashMap<String, String> jobMap = new HashMap<>();
/**
* true -> male
* false -> female
*/
private final HashMap<String, Boolean> sexMap = new HashMap<>();
public String getJob(String name) {
return jobMap.get(name);
}
public Boolean getSex(String name) {
return sexMap.get(name);
}
public void addMan(@NotNull String name,@NotNull Boolean sex, String job) {
sexMap.put(name, sex);
if (job != null) {
jobMap.put(name, job);
}
}
}
/**
* 客户端
*/
public class InterpreterTemplateClient {
public static void main(String[] args) throws Exception {
final Context context = new Context();
context.addMan("小坤", true, "程序员");
context.addMan("小红", false, "教师");
context.addMan("小白", false, null);
context.addMan("小黑", true, "军人");
// 是否四个人都有工作 且 有人为男性?
AbstractExpression expression = new AndExpression(
new AndExpression(
new AndExpression(
new HasJobExpression("小坤"),
new HasJobExpression("小黑")
),
new AndExpression(
new HasJobExpression("小红"),
// 小白没有工作会返回false!!!
new HasJobExpression("小白")
)
),
new OrExpression(
new OrExpression(
new IsMaleExpression("小红"),
new IsMaleExpression("小白")
),
new OrExpression(
new IsMaleExpression("小坤"),
// 由于小坤已经是男性,后续的小黑被短路了,不会进行判断
new IsMaleExpression("小黑")
)
)
);
// 查看并打印结果
System.out.println("是否四个人都有工作 且 有人为女性?" + (expression.interpret(context) ? "是" : "否"));
}
}
解释器模式是一种设计模式,用于创建能解释特定语言的解析器。它通过定义文法和解释规则,使得对简单语言或表达式的解释变得容易,但可能会导致执行效率较低和类膨胀的问题。适用于文法简单、需要解释执行的场景,如 XML 文档解释。模式包括抽象表达式、终结符表达式、非终结符表达式和环境角色四个部分。
2601

被折叠的 条评论
为什么被折叠?



