一、模式介绍
1.1、定义
解释器模式为某个语言定义它的语法(或者叫文法)表示,并定义一个解释器用来处理这个语法。也就是说,用变易语言的方式来分析应用中的实例。这种模式实现了语法表达式处理的接口,该接口解释一个特定的上下文。
1.2、优点
- 扩展性好。由于解释器模式中使用类来表示语言的语法规则,因此可以通过继承等机制来改变或扩展
- 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其语法较为容易
1.3、缺点
- 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦
- 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的语法规则很多时,类的个数将急剧增加,导致系统难以管理与维护
- 可应用的常见比较少。在软件开发中,需要定义语言语法的应用实例非常少,所以这种模式很少被使用到
二、结构与实现
解释器模式的结构和组合模式相似,不过其包含的组成元素比组合模式多。组合模式对象结构型模式,解释器模式是类行为型模式。
2.1、结构
- 抽象表达式角色(AbstractExpression):定义解释器的接口,约定解释的解释操作,主要包含解释方法 interpret
- 终结符表达式角色(TerminalExpression): 是抽象表达式的子类,用来实现语法中与终结符相关的操作,语法中的每一个终结符都有一个具体终结表达式与之相对应
- 非终结符表达式角色(NonterminalExpression):也是抽象表达式的子类,用来实现语法中与非终结符相关的操作,语法中的每条规则都对应一个非终结符表达式
- 环境角色(Context):通常包含各个解释器需要的数据或是公共的功能,一般用来传递所有解释器共享的数据,后面的解释器可以从这里获取这些值
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,也可以通过环境角色间接访问解释器的解释方法
2.2、实现
2.2.1、类图
2.2.2、AbstractExpression
package com.erlang.interpreter;
/**
* @description: 抽象表达式类
* @author: erlang
* @since: 2022-02-20 20:56
*/
public interface AbstractExpression {
/**
* 解释方法
*
* @param info 表达式
* @return true|false
*/
boolean interpret(String info);
}
2.2.3、TerminalExpression
package com.erlang.interpreter;
import java.util.HashSet;
import java.util.Set;
/**
* @description: 终结符表达式类
* @author: erlang
* @since: 2022-02-20 20:57
*/
public class TerminalExpression implements AbstractExpression {
private Set<String> expressions = new HashSet<>();
public TerminalExpression(String[] data) {
for (int i = 0; i < data.length; i++) {
expressions.add(data[i]);
}
}
@Override
public boolean interpret(String info) {
return expressions.contains(info);
}
}
2.2.4、AndExpression
package com.erlang.interpreter;
/**
* @description: 非终结表达式
* @author: erlang
* @since: 2022-02-20 20:58
*/
public class AndExpression implements AbstractExpression {
private AbstractExpression city;
private AbstractExpression person;
public AndExpression(AbstractExpression city, AbstractExpression person) {
this.city = city;
this.person = person;
}
@Override
public boolean interpret(String info) {
String[] arr = info.split("的");
return city.interpret(arr[0]) && person.interpret(arr[1]);
}
}
2.2.5、Context
package com.erlang.interpreter;
/**
* @description: 环境类
* @author: erlang
* @since: 2022-02-20 20:55
*/
public class Context {
private String[] cities = {"北京", "南京"};
private String[] persons = {"老人", "儿童", "退伍"};
private AbstractExpression cityPerson;
public Context() {
AbstractExpression city = new TerminalExpression(cities);
AbstractExpression person = new TerminalExpression(persons);
cityPerson = new AndExpression(city, person);
}
public void free(String info) {
boolean ok = cityPerson.interpret(info);
if (ok) {
System.out.println(info + ",您本次乘车免费!");
} else {
System.out.println(info + ",不在免费范围内,扣费 1 元!");
}
}
}
2.2.6、InterpreterClient
package com.erlang.interpreter;
/**
* @description: 解释器模式客户端测试
* @author: erlang
* @since: 2022-02-20 21:09
*/
public class InterpreterClient {
public static void main(String[] args) {
Context bus = new Context();
bus.free("北京的老人");
bus.free("南京的年轻人");
bus.free("上海的妇女");
bus.free("南京的儿童");
bus.free("江西的儿童");
}
}
2.2.7、执行结果
北京的老人,您本次乘车免费!
南京的年轻人,不在免费范围内,扣费 1 元!
上海的妇女,不在免费范围内,扣费 1 元!
南京的儿童,您本次乘车免费!
江西的儿童,不在免费范围内,扣费 1 元!