解释器模式(Interpreter Pattern)案例详解
模式概述
解释器模式定义了一个语言的文法,并建立一个解释器来解释该语言中的句子,它属于行为型模式,适用于需要解释特定语法的场景。

案例一:数学表达式解释器
这是一个最经典的案例,用于解释和计算简单的数学表达式。
// 抽象表达式
interface Expression {
int interpret();
}
// 终结符表达式 - 数字
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
// 非终结符表达式 - 加法
class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}
// 非终结符表达式 - 减法
class SubtractExpression implements Expression {
private Expression left;
private Expression right;
public SubtractExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() - right.interpret();
}
}
// 非终结符表达式 - 乘法
class MultiplyExpression implements Expression {
private Expression left;
private Expression right;
public MultiplyExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() * right.interpret();
}
}
// 非终结符表达式 - 除法
class DivideExpression implements Expression {
private Expression left;
private Expression right;
public DivideExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
int divisor = right.interpret();
if (divisor == 0) {
throw new ArithmeticException("除数不能为0");
}
return left.interpret() / divisor;
}
}
// 客户端测试类
public class ExpressionDemo {
public static void main(String[] args) {
// 构建表达式: (10 + 20) * 3 - 5
Expression expression = new SubtractExpression(
new MultiplyExpression(
new AddExpression(
new NumberExpression(10),
new NumberExpression(20)
),
new NumberExpression(3)
),
new NumberExpression(5)
);
int result = expression.interpret();
System.out.println("(10 + 20) * 3 - 5 = " + result); // 输出: 85
}
}
案例二:SQL查询解释器
这是一个更复杂的实际应用案例,模拟简单的SQL查询解析。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// 上下文 - 存储数据
class QueryContext {
private List<Map<String, String>> data;
private Map<String, String> params;
public QueryContext() {
this.data = new ArrayList<>();
this.params = new HashMap<>();
}
public void addRow(Map<String, String> row) {
data.add(row);
}
public void addParams(Map<String, String> params) {
this.params.putAll(params);
}
public List<Map<String, String>> getData() {
return data;
}
public String getValue(Map<String, String> row, String column) {
String value = row.get(column);
if (value == null && params.containsKey(column)) {
return params.get(column);
}
return value;
}
}
// 抽象表达式
interface QueryExpression {
List<Map<String, String>> interpret(QueryContext context);
}
// 终结符表达式 - 选择操作
class SelectExpression implements QueryExpression {
private String table;
private WhereExpression where;
public SelectExpression(String table, WhereExpression where) {
this.table = table;
this.where = where;
}
@Override
public List<Map<String, String>> interpret(QueryContext context) {
List<Map<String, String>> result = new ArrayList<>();
for (Map<String, String> row : context.getData()) {
if (where == null || where.interpret(context, row)) {
result.add(row);
}
}
return result;
}
}
// 条件表达式 - 用于WHERE子句
interface WhereExpression {
boolean interpret(QueryContext context, Map<String, String> row);
}
// 等于条件
class EqualsExpression implements WhereExpression {
private String column;
private String value;
public EqualsExpression(String column, String value) {
this.column = column;
this.value = value;
}
@Override
public boolean interpret(QueryContext context, Map<String, String> row) {
String actualValue = context.getValue(row, column);
return value.equals(actualValue);
}
}
// 不等于条件
class NotEqualsExpression implements WhereExpression {
private String column;
private String value;
public NotEqualsExpression(String column, String value) {
this.column = column;
this.value = value;
}
@Override
public boolean interpret(QueryContext context, Map<String, String> row) {
String actualValue = context.getValue(row, column);
return !value.equals(actualValue);
}
}
// AND条件
class AndExpression implements WhereExpression {
private WhereExpression left;
private WhereExpression right;
public AndExpression(WhereExpression left, WhereExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(QueryContext context, Map<String, String> row) {
return left.interpret(context, row) && right.interpret(context, row);
}
}
// OR条件
class OrExpression implements WhereExpression {
private WhereExpression left;
private WhereExpression right;
public OrExpression(WhereExpression left, WhereExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(QueryContext context, Map<String, String> row) {
return left.interpret(context, row) || right.interpret(context, row);
}
}
// 客户端测试
public class SQLQueryDemo {
public static void main(String[] args) {
// 准备测试数据
QueryContext context = new QueryContext();
Map<String, String> row1 = new HashMap<>();
row1.put("name", "张三");
row1.put("age", "25");
row1.put("city", "北京");
context.addRow(row1);
Map<String, String> row2 = new HashMap<>();
row2.put("name", "李四");
row2.put("age", "30");
row2.put("city", "上海");
context.addRow(row2);
Map<String, String> row3 = new HashMap<>();
row3.put("name", "王五");
row3.put("age", "25");
row3.put("city", "北京");
context.addRow(row3);
// 构建查询: SELECT * FROM users WHERE age = 25 AND city = '北京'
WhereExpression where = new AndExpression(
new EqualsExpression("age", "25"),
new EqualsExpression("city", "北京")
);
SelectExpression select = new SelectExpression("users", where);
List<Map<String, String>> result = select.interpret(context);
System.out.println("查询结果:");
for (Map<String, String> row : result) {
System.out.println("姓名: " + row.get("name") +
", 年龄: " + row.get("age") +
", 城市: " + row.get("city"));
}
}
}
案例三:日期格式解释器
import java.text.SimpleDateFormat;
import java.util.Date;
// 日期上下文
class DateContext {
private String dateStr;
private String format;
public DateContext(String dateStr, String format) {
this.dateStr = dateStr;
this.format = format;
}
public String getDateStr() {
return dateStr;
}
public String getFormat() {
return format;
}
}
// 抽象表达式
interface DateExpression {
String interpret(DateContext context);
}
// 年月日解析
class YearMonthDayExpression implements DateExpression {
@Override
public String interpret(DateContext context) {
String dateStr = context.getDateStr();
String year = dateStr.substring(0, 4);
String month = dateStr.substring(4, 6);
String day = dateStr.substring(6, 8);
String format = context.getFormat();
format = format.replace("YYYY", year);
format = format.replace("MM", month);
format = format.replace("DD", day);
return format;
}
}
// 时间解析
class TimeExpression implements DateExpression {
@Override
public String interpret(DateContext context) {
String dateStr = context.getDateStr();
if (dateStr.length() >= 14) {
String hour = dateStr.substring(8, 10);
String minute = dateStr.substring(10, 12);
String second = dateStr.substring(12, 14);
String format = context.getFormat();
format = format.replace("HH", hour);
format = format.replace("mm", minute);
format = format.replace("SS", second);
return format;
}
return context.getFormat();
}
}
// 完整日期解释器
class CompleteDateExpression implements DateExpression {
private YearMonthDayExpression datePart;
private TimeExpression timePart;
public CompleteDateExpression() {
this.datePart = new YearMonthDayExpression();
this.timePart = new TimeExpression();
}
@Override
public String interpret(DateContext context) {
String datePartResult = datePart.interpret(context);
String timePartResult = timePart.interpret(context);
StringBuilder result = new StringBuilder();
if (context.getFormat().contains("YYYY")) {
result.append(datePartResult);
}
if (context.getFormat().contains("HH")) {
if (result.length() > 0) {
result.append(" ");
}
result.append(timePartResult.split(" ")[0]);
}
return result.toString();
}
}
// 客户端测试
public class DateExpressionDemo {
public static void main(String[] args) {
String dateStr = "20240115143025"; // 2024年1月15日 14:30:25
// 格式1:年月日
DateContext context1 = new DateContext(dateStr, "YYYY-MM-DD");
DateExpression expression1 = new YearMonthDayExpression();
System.out.println("日期格式1: " + expression1.interpret(context1));
// 格式2:带时间
DateContext context2 = new DateContext(dateStr, "YYYY/MM/DD HH:mm:SS");
DateExpression expression2 = new CompleteDateExpression();
System.out.println("日期格式2: " + expression2.interpret(context2));
}
}
模式总结
优点:
- 易于改变和扩展文法:新增表达式类即可扩展功能
- 实现文法容易:每个文法规则的实现都在单独的类中
- 易于实现简单的语言:适合简单的语法解析
缺点:
- 难以维护复杂文法:类数量会大量增加
- 执行效率较低:涉及大量的递归调用
- 不适合复杂语法:过于复杂的语法会使代码结构混乱
适用场景:
- 需要解释执行的语言,且语法相对简单
- 语法规则频繁变化
- 可以表示为语法树的语言
- 对效率要求不高的场景
注意事项:
- 当语法规则较多时,考虑使用其他解析方案(如Antlr)
- 可以使用Flyweight模式共享终结符表达式
- 可以结合Visitor模式来遍历抽象语法树