设计模式手册014:解释器模式 - 语言解释的优雅实现
本文是「设计模式手册」系列第014篇,我们将深入探讨解释器模式,这种模式给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
1. 场景:我们为何需要解释器模式?
在软件开发中,我们有时需要解释和执行特定语法或规则的表达式:
- 数学表达式计算:解析和计算"1 + 2 * 3"这样的表达式
- 规则引擎:处理业务规则如"年龄 > 18 AND 信用分 > 600"
- 查询语言:解析SQL查询条件"WHERE name = 'John' AND age > 25"
- 配置文件解析:处理复杂的配置语法
- 领域特定语言(DSL):为特定领域创建专用语言
传统做法的困境:
java
// 硬编码的表达式解析 - 难以维护和扩展
public class SimpleExpressionCalculator {
public static int calculate(String expression) {
// 简单的加减法解析
if (expression.contains("+")) {
String[] parts = expression.split("\\+");
return Integer.parseInt(parts[0].trim()) + Integer.parseInt(parts[1].trim());
} else if (expression.contains("-")) {
String[] parts = expression.split("-");
return Integer.parseInt(parts[0].trim()) - Integer.parseInt(parts[1].trim());
} else if (expression.contains("*")) {
String[] parts = expression.split("\\*");
return Integer.parseInt(parts[0].trim()) * Integer.parseInt(parts[1].trim());
} else if (expression.contains("/")) {
String[] parts = expression.split("/");
return Integer.parseInt(parts[0].trim()) / Integer.parseInt(parts[1].trim());
}
// 如果表达式更复杂,比如 "1 + 2 * 3",这种简单解析就会出错
throw new IllegalArgumentException("不支持的表达式: " + expression);
}
// 问题:无法处理复杂的嵌套表达式
// 问题:每增加一种操作符就要修改代码
// 问题:没有考虑运算符优先级
}
// 使用示例
public class TraditionalExpression {
public static void main(String[] args) {
System.out.println(SimpleExpressionCalculator.calculate("1 + 2")); // 3
System.out.println(SimpleExpressionCalculator.calculate("5 - 3")); // 2
// 这个会得到错误结果,因为简单分割无法处理运算符优先级
// System.out.println(SimpleExpressionCalculator.calculate("1 + 2 * 3")); // 错误!
}
}
这种实现的痛点:
- 硬编码解析逻辑:表达式语法变化时需要修改代码
- 无法处理复杂语法:嵌套表达式、运算符优先级等
- 违反开闭原则:新增语法元素需要修改现有代码
- 难以维护:解析逻辑复杂且难以理解
2. 解释器模式:定义与本质
2.1 模式定义
解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
2.2 核心角色
java
// 抽象表达式:声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享
public interface Expression {
int interpret(Map<String, Integer> context);
}
// 终结符表达式:实现与文法中的终结符相关联的解释操作
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
public NumberExpression(String number) {
this.number = Integer.parseInt(number);
}
@Override
public int interpret(Map<String, Integer> context) {
return number;
}
}
// 变量表达式
public class VariableExpression implements Expression {
private String variableName;
public VariableExpression(String variableName) {
this.variableName = variableName;
}
@Override
public int interpret(Map<String, Integer> context) {
Integer value = context.get(variableName);
if (value == null) {
throw new IllegalArgumentException("变量未定义: " + variableName);
}
return value;
}
}
// 非终结符表达式 - 加法运算
public 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(Map<String, Integer> context) {
return left.interpret(context) + right.interpret(context);
}
}
// 非终结符表达式 - 减法运算
public 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(Map<String, Integer> context) {
return left.interpret(context) - right.interpret(context);
}
}
// 非终结符表达式 - 乘法运算
public 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(Map<String, Integer> context) {
return left.interpret(context) * right.interpret(context);
}
}
// 非终结符表达式 - 除法运算
public 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(Map<String, Integer> context) {
int divisor = right.interpret(context);
if (divisor == 0) {
throw new ArithmeticException("除零错误");
}
return left.interpret(context) / divisor;
}
}
3. 深入理解:解释器模式的多维视角
3.1 第一重:抽象语法树(AST)的构建
核心概念:解释器模式的核心是构建抽象语法树来表示语言的语法结构
java
// 表达式构建器 - 用于构建抽象语法树
public class ExpressionBuilder {
public static Expression build(String expression) {
// 移除所有空格
expression = expression.replaceAll("\\s+", "");
// 处理括号表达式
return parseExpression(expression);
}
private static Expression parseExpression(String expr) {
// 查找最低优先级的操作符(从右向左查找,因为左结合性)
int index = findLowestPriorityOperator(expr);
if (index != -1) {
char operator = expr.charAt(index);
Expression left = parseExpression(expr.substring(0, index));
Expression right = parseExpression(expr.substring(index + 1));
switch (operator) {
case '+': return new AddExpression(left, right);
case '-': return new SubtractExpression(left, right);
case '*': return new MultiplyExpression(left, right);
case '/': return new DivideExpression(left, right);
default: throw new IllegalArgumentException("未知操作符: " + operator);
}
}
// 如果是数字
if (expr.matches("\\d+")) {
return new NumberExpression(expr);
}
// 如果是变量
if (expr.matches("[a-zA-Z_][a-zA-Z_0-9]*")) {
return new VariableExpression(expr);
}
// 如果是括号表达式
if (expr.startsWith("(") && expr.endsWith(")")) {
return parseExpression(expr.substring(1, expr.length() - 1));
}
throw new IllegalArgumentException("无法解析的表达式: " + expr);
}
private static int findLowestPriorityOperator(String expr) {
int parenCount = 0;
int index = -1;
int lowestPriority = Integer.MAX_VALUE;
// 从右向左扫描,找到优先级最低的操作符
for (int i = expr.length() - 1; i >= 0; i--) {
char c = expr.charAt(i);
if (c == ')') parenCount++;
else if (c == '(') parenCount--;
if (parenCount == 0) {
int priority = getOperatorPriority(c);
if (priority != -1 && priority < lowestPriority) {
lowestPriority = priority;
index = i;
}
}
}
return index;
}
private static int getOperatorPriority(char operator) {
switch (operator) {
case '+':
case '-': return 1; // 低优先级
case '*':
case '/': return 2; // 高优先级
default: return -1; // 不是操作符
}
}
}
// 使用示例
public class ExpressionTreeDemo {
public static void main(String[] args) {
// 构建表达式: (a + b) * c - 10
Expression expression = ExpressionBuilder.build("(a + b) * c - 10");
// 设置变量值
Map<String, Integer> context = new HashMap<>();
context.put("a", 5);
context.put("b", 3);
context.put("c", 2);
// 解释执行
int result = expression.interpret(context);
System.out.println("(5 + 3) * 2 - 10 = " + result); // 输出: 6
}
}
3.2 第二重:文法规则的定义
java
// 更复杂的文法规则支持
public class BooleanExpression implements Expression {
private Expression left;
private Expression right;
private String operator;
public BooleanExpression(Expression left, Expression right, String operator) {
this.left = left;
this.right = right;
this.operator = operator;
}
@Override
public int interpret(Map<String, Integer> context) {
int leftVal = left.interpret(context);
int rightVal = right.interpret(context);
switch (operator) {
case ">": return leftVal > rightVal ? 1 : 0;
case "<": return leftVal < rightVal ? 1 : 0;
case ">=": return leftVal >= rightVal ? 1 : 0;
case "<=": return leftVal <= rightVal ? 1 : 0;
case "==": return leftVal == rightVal ? 1 : 0;
case "!=": return leftVal != rightVal ? 1 : 0;
default: throw new IllegalArgumentException("未知比较操作符: " + operator);
}
}
}
public class LogicalExpression implements Expression {
private Expression left;
private Expression right;
private String operator;
public LogicalExpression(Expression left, Expression right, String operator) {
this.left = left;
this.right = right;
this.operator = operator;
}
@Override
public int interpret(Map<String, Integer> context) {
int leftVal = left.interpret(context);
int rightVal = right.interpret(context);
switch (operator) {
case "AND": return (leftVal != 0 && rightVal != 0) ? 1 : 0;
case "OR": return (leftVal != 0 || rightVal != 0) ? 1 : 0;
default: throw new IllegalArgumentException("未知逻辑操作符: " + operator);
}
}
}
public class NotExpression implements Expression {
private Expression expression;
public NotExpression(Expression expression) {
this.expression = expression;
}
@Override
public int interpret(Map<String, Integer> context) {
int value = expression.interpret(context);
return value == 0 ? 1 : 0;
}
}
3.3 第三重:解释器上下文
java
// 增强的解释器上下文
public class InterpreterContext {
private Map<String, Integer> variables = new HashMap<>();
private Map<String, Function<Object[], Object>> functions = new HashMap<>();
public InterpreterContext() {
registerBuiltinFunctions();
}
public void setVariable(String name, int value) {
variables.put(name, value);
}
public int getVariable(String name) {
Integer value = variables.get(name);
if (value == null) {
throw new IllegalArgumentException("变量未定义: " + name);
}
return value;
}
public void registerFunction(String name, Function<Object[], Object> function) {
functions.put(name, function);
}
public Object callFunction(String name, Object[] args) {
Function<Object[], Object> function = functions.get(name);
if (function == null) {
throw new IllegalArgumentException("函数未定义: " + name);
}
return function.apply(args);
}
private void registerBuiltinFunctions() {
// 注册内置函数
registerFunction("max", args -> {
if (args.length < 2) throw new IllegalArgumentException("max函数需要至少2个参数");
return Math.max(((Number) args[0]).intValue(), ((Number) args[1]).intValue());
});
registerFunction("min", args -> {
if (args.length < 2) throw new IllegalArgumentException("min函数需要至少2个参数");
return Math.min(((Number) args[0]).intValue(), ((Number) args[1]).intValue());
});
registerFunction("sqrt", args -> {
if (args.length != 1) throw new IllegalArgumentException("sqrt函数需要1个参数");
return Math.sqrt(((Number) args[0]).doubleValue());
});
}
}
4. 实战案例:完整的规则引擎
java
// 规则引擎 - 支持复杂的业务规则
public interface RuleExpression {
boolean evaluate(RuleContext context);
String getDescription();
}
// 规则上下文
@Data
public class RuleContext {
private Map<String, Object> facts = new HashMap<>();
public void setFact(String name, Object value) {
facts.put(name, value);
}
public Object getFact(String name) {
return facts.get(name);
}
@SuppressWarnings("unchecked")
public <T> T getFact(String name, Class<T> type) {
Object value = facts.get(name);
return value != null ? (T) value : null;
}
}
// 基础事实表达式
public class FactExpression implements RuleExpression {
private String factName;
private Object expectedValue;
public FactExpression(String factName, Object expectedValue) {
this.factName = factName;
this.expectedValue = expectedValue;
}
@Override
public boolean evaluate(RuleContext context) {
Object actualValue = context.getFact(factName);
return expectedValue.equals(actualValue);
}
@Override
public String getDescription() {
return factName + " = " + expectedValue;
}
}
// 比较表达式
public class ComparisonExpression implements RuleExpression {
private String factName;
private Object value;
private String operator;
public ComparisonExpression(String factName, String operator, Object value) {
this.factName = factName;
this.operator = operator;
this.value = value;
}
@Override
public boolean evaluate(RuleContext context) {
Object factValue = context.getFact(factName);
if (factValue == null) {
return false;
}
// 数值比较
if (factValue instanceof Number && value instanceof Number) {
double factDouble = ((Number) factValue).doubleValue();
double valueDouble = ((Number) value).doubleValue();
switch (operator) {
case ">": return factDouble > valueDouble;
case ">=": return factDouble >= valueDouble;
case "<": return factDouble < valueDouble;
case "<=": return factDouble <= valueDouble;
case "==": return factDouble == valueDouble;
case "!=": return factDouble != valueDouble;
}
}
// 字符串比较
if (factValue instanceof String && value instanceof String) {
String factStr = (String) factValue;
String valueStr = (String) value;
switch (operator) {
case "==": return factStr.equals(valueStr);
case "!=": return !factStr.equals(valueStr);
case "contains": return factStr.contains(valueStr);
case "startsWith": return factStr.startsWith(valueStr);
case "endsWith": return factStr.endsWith(valueStr);
}
}
// 布尔比较
if (factValue instanceof Boolean && value instanceof Boolean) {
boolean factBool = (Boolean) factValue;
boolean valueBool = (Boolean) value;
switch (operator) {
case "==": return factBool == valueBool;
case "!=": return factBool != valueBool;
}
}
throw new IllegalArgumentException("不支持的比较操作: " + factName + " " + operator + " " + value);
}
@Override
public String getDescription() {
return factName + " " + operator + " " + value;
}
}
// 逻辑表达式
public class AndExpression implements RuleExpression {
private List<RuleExpression> expressions;
public AndExpression(RuleExpression... expressions) {
this.expressions = Arrays.asList(expressions);
}
@Override
public boolean evaluate(RuleContext context) {
for (RuleExpression expression : expressions) {
if (!expression.evaluate(context)) {
return false;
}
}
return true;
}
@Override
public String getDescription() {
return expressions.stream()
.map(RuleExpression::getDescription)
.collect(Collectors.joining(" AND ", "(", ")"));
}
}
public class OrExpression implements RuleExpression {
private List<RuleExpression> expressions;
public OrExpression(RuleExpression... expressions) {
this.expressions = Arrays.asList(expressions);
}
@Override
public boolean evaluate(RuleContext context) {
for (RuleExpression expression : expressions) {
if (expression.evaluate(context)) {
return true;
}
}
return false;
}
@Override
public String getDescription() {
return expressions.stream()
.map(RuleExpression::getDescription)
.collect(Collectors.joining(" OR ", "(", ")"));
}
}
public class NotExpression implements RuleExpression {
private RuleExpression expression;
public NotExpression(RuleExpression expression) {
this.expression = expression;
}
@Override
public boolean evaluate(RuleContext context) {
return !expression.evaluate(context);
}
@Override
public String getDescription() {
return "NOT " + expression.getDescription();
}
}
// 范围表达式
public class RangeExpression implements RuleExpression {
private String factName;
private Number min;
private Number max;
private boolean includeMin;
private boolean includeMax;
public RangeExpression(String factName, Number min, Number max) {
this(factName, min, max, true, true);
}
public RangeExpression(String factName, Number min, Number max, boolean includeMin, boolean includeMax) {
this.factName = factName;
this.min = min;
this.max = max;
this.includeMin = includeMin;
this.includeMax = includeMax;
}
@Override
public boolean evaluate(RuleContext context) {
Object factValue = context.getFact(factName);
if (!(factValue instanceof Number)) {
return false;
}
double value = ((Number) factValue).doubleValue();
double minValue = min.doubleValue();
double maxValue = max.doubleValue();
boolean lowerBound = includeMin ? value >= minValue : value > minValue;
boolean upperBound = includeMax ? value <= maxValue : value < maxValue;
return lowerBound && upperBound;
}
@Override
public String getDescription() {
String lower = includeMin ? "[" : "(";
String upper = includeMax ? "]" : ")";
return factName + " ∈ " + lower + min + ", " + max + upper;
}
}
// 规则引擎
public class RuleEngine {
private List<Rule> rules = new ArrayList<>();
public void addRule(Rule rule) {
rules.add(rule);
}
public List<Rule> evaluate(RuleContext context) {
return rules.stream()
.filter(rule -> rule.evaluate(context))
.collect(Collectors.toList());
}
public Rule findFirstMatch(RuleContext context) {
return rules.stream()
.filter(rule -> rule.evaluate(context))
.findFirst()
.orElse(null);
}
}
// 规则
@Data
public class Rule {
private String name;
private int priority;
private RuleExpression condition;
private String action;
public Rule(String name, int priority, RuleExpression condition, String action) {
this.name = name;
this.priority = priority;
this.condition = condition;
this.action = action;
}
public boolean evaluate(RuleContext context) {
return condition.evaluate(context);
}
public String getDescription() {
return name + ": IF " + condition.getDescription() + " THEN " + action;
}
}
// 使用示例:贷款审批规则引擎
public class LoanApprovalEngine {
public static void main(String[] args) {
// 创建规则引擎
RuleEngine engine = new RuleEngine();
// 定义审批规则
// 规则1:年龄必须 >= 18
Rule ageRule = new Rule("年龄检查", 10,
new ComparisonExpression("age", ">=", 18),
"通过年龄检查");
// 规则2:信用分数 >= 600
Rule creditRule = new Rule("信用检查", 20,
new ComparisonExpression("creditScore", ">=", 600),
"通过信用检查");
// 规则3:收入 >= 30000 或者 有担保人
Rule incomeRule = new Rule("收入检查", 30,
new OrExpression(
new ComparisonExpression("income", ">=", 30000),
new FactExpression("hasGuarantor", true)
),
"通过收入检查");
// 规则4:负债收入比 <= 0.5
Rule debtRule = new Rule("负债检查", 40,
new ComparisonExpression("debtToIncomeRatio", "<=", 0.5),
"通过负债检查");
// 规则5:综合审批规则
Rule approvalRule = new Rule("贷款审批", 100,
new AndExpression(ageRule.getCondition(), creditRule.getCondition(),
incomeRule.getCondition(), debtRule.getCondition()),
"批准贷款申请");
// 规则6:拒绝规则 - 有不良信用记录
Rule rejectionRule = new Rule("信用记录拒绝", 90,
new FactExpression("hasBadCreditHistory", true),
"拒绝贷款:不良信用记录");
// 添加规则到引擎
engine.addRule(ageRule);
engine.addRule(creditRule);
engine.addRule(incomeRule);
engine.addRule(debtRule);
engine.addRule(rejectionRule);
engine.addRule(approvalRule);
// 测试用例1:合格的申请人
System.out.println("=== 测试用例1:合格的申请人 ===");
RuleContext context1 = new RuleContext();
context1.setFact("age", 25);
context1.setFact("creditScore", 650);
context1.setFact("income", 40000);
context1.setFact("debtToIncomeRatio", 0.3);
context1.setFact("hasGuarantor", false);
context1.setFact("hasBadCreditHistory", false);
Rule matchedRule = engine.findFirstMatch(context1);
if (matchedRule != null) {
System.out.println("匹配规则: " + matchedRule.getDescription());
}
// 测试用例2:有不良信用记录的申请人
System.out.println("\n=== 测试用例2:有不良信用记录的申请人 ===");
RuleContext context2 = new RuleContext();
context2.setFact("age", 30);
context2.setFact("creditScore", 700);
context2.setFact("income", 50000);
context2.setFact("debtToIncomeRatio", 0.2);
context2.setFact("hasGuarantor", false);
context2.setFact("hasBadCreditHistory", true);
matchedRule = engine.findFirstMatch(context2);
if (matchedRule != null) {
System.out.println("匹配规则: " + matchedRule.getDescription());
}
// 显示所有匹配的规则
System.out.println("\n=== 所有匹配的规则 ===");
List<Rule> allMatches = engine.evaluate(context1);
allMatches.forEach(rule ->
System.out.println(rule.getDescription()));
}
}
5. Spring框架中的解释器模式
5.1 Spring EL(表达式语言)
java
// 模拟Spring表达式语言解析
@Component
public class SpringExpressionParser {
private final Map<String, Object> context = new HashMap<>();
public void setVariable(String name, Object value) {
context.put(name, value);
}
public Object evaluate(String expression) {
// 简单的Spring EL解析实现
return parseExpression(expression);
}
private Object parseExpression(String expr) {
expr = expr.trim();
// 处理字面量
if (expr.matches("-?\\d+")) {
return Integer.parseInt(expr);
}
if (expr.matches("-?\\d+\\.\\d+")) {
return Double.parseDouble(expr);
}
if (expr.startsWith("'") && expr.endsWith("'")) {
return expr.substring(1, expr.length() - 1);
}
if (expr.startsWith("\"") && expr.endsWith("\"")) {
return expr.substring(1, expr.length() - 1);
}
if ("true".equalsIgnoreCase(expr) || "false".equalsIgnoreCase(expr)) {
return Boolean.parseBoolean(expr);
}
// 处理变量
if (context.containsKey(expr)) {
return context.get(expr);
}
// 处理简单表达式
if (expr.contains("+")) {
String[] parts = expr.split("\\+");
Object left = parseExpression(parts[0]);
Object right = parseExpression(parts[1]);
return add(left, right);
}
if (expr.contains("==")) {
String[] parts = expr.split("==");
Object left = parseExpression(parts[0]);
Object right = parseExpression(parts[1]);
return left.equals(right);
}
// 处理方法调用
if (expr.contains(".")) {
return parseMethodCall(expr);
}
throw new IllegalArgumentException("无法解析表达式: " + expr);
}
private Object add(Object left, Object right) {
if (left instanceof Number && right instanceof Number) {
if (left instanceof Integer && right instanceof Integer) {
return (Integer) left + (Integer) right;
}
return ((Number) left).doubleValue() + ((Number) right).doubleValue();
}
if (left instanceof String || right instanceof String) {
return left.toString() + right.toString();
}
throw new IllegalArgumentException("不支持的操作数类型: " + left.getClass() + " + " + right.getClass());
}
private Object parseMethodCall(String expr) {
// 简单的方法调用解析
String[] parts = expr.split("\\.");
String objectName = parts[0];
String methodPart = parts[1];
Object target = context.get(objectName);
if (target == null) {
throw new IllegalArgumentException("对象未定义: " + objectName);
}
// 解析方法名和参数
if (methodPart.contains("(") && methodPart.endsWith(")")) {
String methodName = methodPart.substring(0, methodPart.indexOf("("));
String argsStr = methodPart.substring(methodPart.indexOf("(") + 1, methodPart.length() - 1);
// 简单参数解析
Object[] args = Arrays.stream(argsStr.split(","))
.map(String::trim)
.map(this::parseExpression)
.toArray();
return invokeMethod(target, methodName, args);
}
// 属性访问
return getProperty(target, methodPart);
}
private Object invokeMethod(Object target, String methodName, Object[] args) {
try {
Class<?>[] paramTypes = Arrays.stream(args)
.map(Object::getClass)
.toArray(Class<?>[]::new);
Method method = target.getClass().getMethod(methodName, paramTypes);
return method.invoke(target, args);
} catch (Exception e) {
throw new RuntimeException("方法调用失败: " + methodName, e);
}
}
private Object getProperty(Object target, String propertyName) {
try {
String getterName = "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
Method getter = target.getClass().getMethod(getterName);
return getter.invoke(target);
} catch (Exception e) {
throw new RuntimeException("属性访问失败: " + propertyName, e);
}
}
}
// 使用Spring EL的示例
@Component
public class BusinessRuleService {
private final SpringExpressionParser expressionParser;
@Autowired
public BusinessRuleService(SpringExpressionParser expressionParser) {
this.expressionParser = expressionParser;
}
public boolean evaluateBusinessRule(String ruleExpression, Map<String, Object> variables) {
// 设置变量
variables.forEach(expressionParser::setVariable);
// 评估表达式
Object result = expressionParser.evaluate(ruleExpression);
if (result instanceof Boolean) {
return (Boolean) result;
}
throw new IllegalArgumentException("规则表达式必须返回布尔值: " + ruleExpression);
}
}
5.2 Spring Security的表达权限控制
java
// 模拟Spring Security的权限表达式
@Component
public class SecurityExpressionParser {
public boolean evaluate(String expression, SecurityContext context) {
return parseSecurityExpression(expression, context);
}
private boolean parseSecurityExpression(String expr, SecurityContext context) {
expr = expr.trim();
// 处理hasRole表达式
if (expr.startsWith("hasRole(") && expr.endsWith(")")) {
String role = expr.substring(8, expr.length() - 1).replace("'", "");
return context.hasRole(role);
}
// 处理hasAnyRole表达式
if (expr.startsWith("hasAnyRole(") && expr.endsWith(")")) {
String rolesStr = expr.substring(11, expr.length() - 1).replace("'", "");
String[] roles = rolesStr.split(",");
return Arrays.stream(roles)
.anyMatch(context::hasRole);
}
// 处理hasAuthority表达式
if (expr.startsWith("hasAuthority(") && expr.endsWith(")")) {
String authority = expr.substring(13, expr.length() - 1).replace("'", "");
return context.hasAuthority(authority);
}
// 处理permitAll表达式
if ("permitAll".equals(expr)) {
return true;
}
// 处理denyAll表达式
if ("denyAll".equals(expr)) {
return false;
}
// 处理逻辑表达式
if (expr.contains(" and ")) {
String[] parts = expr.split(" and ");
return Arrays.stream(parts)
.allMatch(part -> parseSecurityExpression(part, context));
}
if (expr.contains(" or ")) {
String[] parts = expr.split(" or ");
return Arrays.stream(parts)
.anyMatch(part -> parseSecurityExpression(part, context));
}
throw new IllegalArgumentException("未知的安全表达式: " + expr);
}
}
// 安全上下文
@Data
public class SecurityContext {
private UserPrincipal user;
private String requestUri;
private String method;
public boolean hasRole(String role) {
return user != null && user.getRoles().contains(role);
}
public boolean hasAuthority(String authority) {
return user != null && user.getAuthorities().contains(authority);
}
}
// 用户主体
@Data
public class UserPrincipal {
private String username;
private Set<String> roles = new HashSet<>();
private Set<String> authorities = new HashSet<>();
public UserPrincipal(String username, String... roles) {
this.username = username;
this.roles.addAll(Arrays.asList(roles));
}
}
// 使用方法注解进行权限控制
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PreAuthorize {
String value();
}
// 安全拦截器
@Component
public class SecurityInterceptor {
private final SecurityExpressionParser expressionParser;
@Autowired
public SecurityInterceptor(SecurityExpressionParser expressionParser) {
this.expressionParser = expressionParser;
}
public boolean checkPermission(String expression, SecurityContext context) {
return expressionParser.evaluate(expression, context);
}
}
6. 解释器模式的进阶用法
6.1 语法树可视化
java
// 支持可视化的表达式接口
public interface VisualExpression extends Expression {
String toTreeString();
String toTreeString(int indent);
}
// 可可视化的数学表达式
public class VisualAddExpression extends AddExpression implements VisualExpression {
public VisualAddExpression(Expression left, Expression right) {
super(left, right);
}
@Override
public String toTreeString() {
return toTreeString(0);
}
@Override
public String toTreeString(int indent) {
String indentStr = " ".repeat(indent);
StringBuilder sb = new StringBuilder();
sb.append(indentStr).append("AddExpression\n");
if (left instanceof VisualExpression) {
sb.append(((VisualExpression) left).toTreeString(indent + 1));
} else {
sb.append(indentStr).append(" ").append(left).append("\n");
}
if (right instanceof VisualExpression) {
sb.append(((VisualExpression) right).toTreeString(indent + 1));
} else {
sb.append(indentStr).append(" ").append(right).append("\n");
}
return sb.toString();
}
}
// 语法树可视化工具
public class ExpressionTreeVisualizer {
public static void visualize(Expression expression) {
if (expression instanceof VisualExpression) {
System.out.println("表达式语法树:");
System.out.println(((VisualExpression) expression).toTreeString());
} else {
System.out.println("表达式: " + expression);
}
}
public static String generateGraphviz(Expression expression) {
StringBuilder sb = new StringBuilder();
sb.append("digraph ExpressionTree {\n");
sb.append(" node [shape=box];\n");
generateGraphvizNodes(expression, sb, "root");
sb.append("}\n");
return sb.toString();
}
private static void generateGraphvizNodes(Expression expr, StringBuilder sb, String parentId) {
String nodeId = parentId + "_" + System.identityHashCode(expr);
String label = expr.getClass().getSimpleName();
if (expr instanceof NumberExpression) {
label = ((NumberExpression) expr).interpret(null) + "";
} else if (expr instanceof VariableExpression) {
label = ((VariableExpression) expr).interpret(null) + "";
}
sb.append(" ").append(nodeId).append(" [label=\"").append(label).append("\"];\n");
sb.append(" ").append(parentId).append(" -> ").append(nodeId).append(";\n");
// 递归处理子节点
// 这里需要根据具体表达式类型访问其子节点
}
}
6.2 解释器性能优化
java
// 带缓存的解释器
public class CachingExpression implements Expression {
private final Expression expression;
private final Map<Map<String, Integer>, Integer> cache = new ConcurrentHashMap<>();
public CachingExpression(Expression expression) {
this.expression = expression;
}
@Override
public int interpret(Map<String, Integer> context) {
return cache.computeIfAbsent(new HashMap<>(context), k -> expression.interpret(context));
}
}
// 预编译的解释器
public class CompiledExpression implements Expression {
private final Expression expression;
private final Map<String, Integer> fixedContext;
private Integer cachedResult;
public CompiledExpression(Expression expression, Map<String, Integer> fixedContext) {
this.expression = expression;
this.fixedContext = new HashMap<>(fixedContext);
}
@Override
public int interpret(Map<String, Integer> context) {
// 如果上下文与预编译时相同,使用缓存结果
if (cachedResult != null && fixedContext.equals(context)) {
return cachedResult;
}
// 否则重新计算并缓存
cachedResult = expression.interpret(context);
return cachedResult;
}
public void precompute() {
cachedResult = expression.interpret(fixedContext);
}
}
// 解释器工厂
public class ExpressionFactory {
private static final Map<String, Expression> expressionCache = new ConcurrentHashMap<>();
public static Expression getExpression(String expressionStr) {
return expressionCache.computeIfAbsent(expressionStr, k -> {
System.out.println("编译表达式: " + expressionStr);
return ExpressionBuilder.build(expressionStr);
});
}
public static Expression getCachedExpression(String expressionStr) {
Expression baseExpression = getExpression(expressionStr);
return new CachingExpression(baseExpression);
}
}
7. 解释器模式 vs 其他模式
7.1 解释器模式 vs 访问者模式
- 解释器模式:为语言创建解释器,关注语法的表示和解释
- 访问者模式:在不变更各元素类的前提下定义作用于这些元素的新操作
7.2 解释器模式 vs 组合模式
- 解释器模式:专门用于语言解释,有明确的文法规则
- 组合模式:处理部分-整体层次结构,不关注具体语义
7.3 解释器模式 vs 策略模式
- 解释器模式:处理语言文法,构建抽象语法树
- 策略模式:封装算法,在运行时选择不同的算法实现
8. 总结与思考
8.1 解释器模式的优点
- 易于扩展文法:新增语法规则只需要新增表达式类
- 易于实现语法:每个语法规则都可以表示为一个类
- 易于改变和扩展语言:通过继承来改变或扩展语言的文法
- 实现文法简单:文法由很多类表示,易于实现
8.2 解释器模式的缺点
- 执行效率较低:解释器模式通常使用递归或循环调用,性能较低
- 对于复杂文法难以维护:文法规则过多时,类数量会急剧增加
- 应用场景有限:只有在特定领域需要语言解释时才适用
- 难以处理复杂的语法分析:需要配合其他模式如解析器模式
8.3 设计思考
解释器模式的本质是**"语言解释的抽象语法树"**。它通过将语言的文法规则表示为类的层次结构,并构建抽象语法树来解释语言中的句子。
深入思考的角度:
"解释器模式的核心价值在于它为特定领域语言(DSL)提供了一种优雅的实现方式。通过将文法规则对象化,我们可以构建灵活且可扩展的语言处理系统。"
在实际应用中,解释器模式有很多优秀的实践:
- 正则表达式引擎
- SQL查询解释器
- 业务规则引擎
- 数学表达式计算器
- 模板引擎
从系统设计的角度看,解释器模式特别适合以下场景:
- 当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时
- 文法比较简单,对于复杂的文法,文法的类层次变得庞大而无法管理
- 效率不是关键问题,因为解释器模式通常效率不高
最佳实践建议:
- 仔细设计文法规则,确保文法足够简单
- 考虑使用解析器生成工具(如ANTLR)来处理复杂文法
- 为解释器添加缓存机制提高性能
- 考虑使用访问者模式来遍历抽象语法树
- 为表达式提供良好的调试和可视化支持
使用场景判断:
- 适合:领域特定语言、简单文法、规则引擎、查询语言
- 不适合:复杂文法、高性能要求、通用编程语言
下一篇预告:设计模式手册015 - 迭代器模式:如何提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示?
版权声明:本文为CSDN博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。