欢迎光临
我们一直在努力

【从零入门23种设计模式15】行为型之解释器模式

一、解释器模式核心定义

解释器模式是行为型设计模式的一种,核心目的是:

定义一个语言的文法(语法规则),并构建一个解释器来解释该语言中的句子(表达式)。简单来说,就是自定义一套 “小语言 / 规则”,并写代码来解析执行这套规则。

核心解决的问题
  • 自定义规则解析:当系统需要处理固定格式的规则 / 表达式(如数学公式、权限规则、过滤条件)时,用解释器模式将规则拆解为可执行的 “语法单元”;
  • 规则复用与扩展:相同类型的规则可通过组合语法单元实现复用,新增规则只需新增语法单元(而非重构整个解析逻辑)。
  • 生活类比(快速理解)
    • 场景 1:计算器计算 1 + 2 * 3
      • 文法(规则):四则运算规则(先乘除后加减);
      • 解释器:计算器程序(拆解表达式为 “数字”“+”“*” 等单元,按规则计算);
      • 句子:1 + 2 * 3(需要解析执行的表达式)。
    • 场景 2:快递运费规则 重量>10kg 且 距离>500km → 运费=重量*2 + 距离*0.1
      • 文法:逻辑判断(>)、算术运算(*+)、条件分支;
      • 解释器:运费计算程序(解析规则并执行);
      • 句子:具体的运费规则表达式。
    角色
    角色职责类比(计算器场景)
    抽象表达式(AbstractExpression) 定义解释器的统一接口(核心:interpret()方法) 运算规则接口(规定 “计算” 行为)
    终结符表达式(TerminalExpression) 文法中的最小单元(不可再拆分),如数字、常量、基础运算符 数字(1/2/3)、变量(x/y)
    非终结符表达式(NonTerminalExpression) 文法中的复合单元(由多个表达式组合而成),如加减乘除、逻辑运算 加法(+)、乘法(*)
    上下文(Context) 存储解释器的全局状态(如变量值、计算结果),供所有表达式共享 存储数字值、运算中间结果
    客户端(Client) 构建表达式树(组合终结符 / 非终结符),调用解释器执行 用户输入表达式,触发计算
    核心 UML 类图


    二、基础版实现(四则运算解释器)

    以 “支持加减乘除的简单计算器” 为例,实现解释器模式的核心逻辑 —— 这是解释器模式最经典的入门案例。

    1. 步骤 1:定义上下文(存储变量 / 结果)

    import java.util.HashMap;
    import java.util.Map;

    /**
    * 上下文:存储表达式中的变量值和计算状态
    */
    public class CalculatorContext {
    // 变量名 → 值(如 "a" → 10, "b" → 20)
    private final Map<String, Integer> variables = new HashMap<>();

    /**
    * 设置变量值
    */
    public void setVariable(String name, int value) {
    variables.put(name, value);
    }

    /**
    * 获取变量值
    */
    public int getVariable(String name) {
    return variables.getOrDefault(name, 0);
    }
    }

    2. 步骤 2:定义抽象表达式

    /**
    * 抽象表达式:四则运算表达式的统一接口
    */
    public abstract class AbstractExpression {
    /**
    * 解释表达式并返回计算结果
    * @param context 上下文(存储变量值)
    * @return 计算结果
    */
    public abstract int interpret(CalculatorContext context);
    }

    3. 步骤 3:实现终结符表达式(数字 / 变量)

    /**
    * 终结符表达式:变量表达式(如 a、b、x)
    * 最小语法单元,不可再拆分
    */
    public class VariableExpression extends AbstractExpression {
    private final String variableName; // 变量名(如 "a")

    public VariableExpression(String variableName) {
    this.variableName = variableName;
    }

    @Override
    public int interpret(CalculatorContext context) {
    // 直接从上下文获取变量值(核心:终结符仅读取/返回值,无计算)
    return context.getVariable(variableName);
    }
    }

    4. 步骤 4:实现非终结符表达式(加减乘除)

    /**
    * 非终结符表达式:加法表达式(由两个子表达式组成)
    */
    public class AddExpression extends AbstractExpression {
    private final AbstractExpression left; // 左表达式
    private final AbstractExpression right; // 右表达式

    public AddExpression(AbstractExpression left, AbstractExpression right) {
    this.left = left;
    this.right = right;
    }

    @Override
    public int interpret(CalculatorContext context) {
    // 先解释左、右表达式,再执行加法(核心:非终结符组合子表达式计算)
    return left.interpret(context) + right.interpret(context);
    }
    }

    /**
    * 非终结符表达式:乘法表达式
    */
    public class MultiplyExpression extends AbstractExpression {
    private final AbstractExpression left;
    private final AbstractExpression right;

    public MultiplyExpression(AbstractExpression left, AbstractExpression right) {
    this.left = left;
    this.right = right;
    }

    @Override
    public int interpret(CalculatorContext context) {
    return left.interpret(context) * right.interpret(context);
    }
    }

    5. 步骤 5:客户端(构建表达式树并执行)

    /**
    * 客户端:构建四则运算表达式树,执行解释计算
    * 示例:计算 a + b * c (a=1, b=2, c=3 → 1+2*3=7)
    */
    public class InterpreterClient {
    public static void main(String[] args) {
    // 1. 创建上下文,设置变量值
    CalculatorContext context = new CalculatorContext();
    context.setVariable("a", 1);
    context.setVariable("b", 2);
    context.setVariable("c", 3);

    // 2. 构建表达式树:a + (b * c)
    // 终结符:a、b、c
    AbstractExpression a = new VariableExpression("a");
    AbstractExpression b = new VariableExpression("b");
    AbstractExpression c = new VariableExpression("c");
    // 非终结符:b * c
    AbstractExpression multiply = new MultiplyExpression(b, c);
    // 非终结符:a + (b * c)
    AbstractExpression add = new AddExpression(a, multiply);

    // 3. 解释执行表达式
    int result = add.interpret(context);
    System.out.println("表达式 a + b * c 的计算结果:" + result); // 输出 7

    // 扩展:修改变量值,重新计算(无需修改表达式树)
    context.setVariable("a", 10);
    int result2 = add.interpret(context);
    System.out.println("修改a=10后,计算结果:" + result2); // 输出 16
    }
    }

    输出结果

    表达式 a + b * c 的计算结果:7
    修改a=10后,计算结果:16

    三、Spring 实战版(权限规则解释器)

    在业务开发中,解释器模式最常见的场景是权限规则解析、动态过滤条件解析。以下实现一个 “用户权限规则解释器”,支持解析如 role=ADMIN 且 dept=IT 或 level>5 的规则。

    1. 依赖准备(Spring Boot)

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>3.2.3</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </dependency>
    </dependencies>

    2. 核心模型定义

    import lombok.Data;

    /**
    * 用户信息(上下文数据)
    */
    @Data
    public class User {
    private String userId;
    private String role; // 角色:ADMIN/USER/GUEST
    private String dept; // 部门:IT/HR/Finance
    private int level; // 等级:1-10
    }

    /**
    * 权限上下文:存储用户信息和规则解析状态
    */
    @Data
    public class PermissionContext {
    private User user; // 当前用户
    private boolean result; // 解析结果(是否有权限)
    }

    3. 抽象表达式(权限规则)

    /**
    * 抽象表达式:权限规则表达式
    */
    public abstract class AbstractPermissionExpression {
    /**
    * 解释权限规则
    * @param context 权限上下文
    * @return 是否满足规则
    */
    public abstract boolean interpret(PermissionContext context);
    }

    4. 终结符表达式(基础规则)

    /**
    * 终结符表达式:角色匹配规则(如 role=ADMIN)
    */
    public class RoleExpression extends AbstractPermissionExpression {
    private final String targetRole; // 目标角色

    public RoleExpression(String targetRole) {
    this.targetRole = targetRole;
    }

    @Override
    public boolean interpret(PermissionContext context) {
    // 核心:匹配用户角色
    return targetRole.equals(context.getUser().getRole());
    }
    }

    /**
    * 终结符表达式:部门匹配规则(如 dept=IT)
    */
    public class DeptExpression extends AbstractPermissionExpression {
    private final String targetDept; // 目标部门

    public DeptExpression(String targetDept) {
    this.targetDept = targetDept;
    }

    @Override
    public boolean interpret(PermissionContext context) {
    return targetDept.equals(context.getUser().getDept());
    }
    }

    /**
    * 终结符表达式:等级大于规则(如 level>5)
    */
    public class LevelGtExpression extends AbstractPermissionExpression {
    private final int targetLevel; // 目标等级

    public LevelGtExpression(int targetLevel) {
    this.targetLevel = targetLevel;
    }

    @Override
    public boolean interpret(PermissionContext context) {
    return context.getUser().getLevel() > targetLevel;
    }
    }

    5. 非终结符表达式(逻辑组合)

    /**
    * 非终结符表达式:逻辑与(AND)
    */
    public class AndExpression extends AbstractPermissionExpression {
    private final AbstractPermissionExpression left;
    private final AbstractPermissionExpression right;

    public AndExpression(AbstractPermissionExpression left, AbstractPermissionExpression right) {
    this.left = left;
    this.right = right;
    }

    @Override
    public boolean interpret(PermissionContext context) {
    // 左、右表达式都满足才返回true
    return left.interpret(context) && right.interpret(context);
    }
    }

    /**
    * 非终结符表达式:逻辑或(OR)
    */
    public class OrExpression extends AbstractPermissionExpression {
    private final AbstractPermissionExpression left;
    private final AbstractPermissionExpression right;

    public OrExpression(AbstractPermissionExpression left, AbstractPermissionExpression right) {
    this.left = left;
    this.right = right;
    }

    @Override
    public boolean interpret(PermissionContext context) {
    // 左、右表达式有一个满足就返回true
    return left.interpret(context) || right.interpret(context);
    }
    }

    6. 解释器管理器(Spring Bean)

    import org.springframework.stereotype.Component;

    /**
    * 权限规则解释器管理器(统一解析入口)
    */
    @Component
    public class PermissionInterpreterManager {
    /**
    * 解析权限规则:role=ADMIN 且 dept=IT 或 level>5
    */
    public boolean checkPermission(User user) {
    // 1. 创建上下文
    PermissionContext context = new PermissionContext();
    context.setUser(user);

    // 2. 构建规则表达式树:(role=ADMIN AND dept=IT) OR level>5
    AbstractPermissionExpression adminRole = new RoleExpression("ADMIN");
    AbstractPermissionExpression itDept = new DeptExpression("IT");
    AbstractPermissionExpression andExpr = new AndExpression(adminRole, itDept);
    AbstractPermissionExpression levelGt5 = new LevelGtExpression(5);
    AbstractPermissionExpression orExpr = new OrExpression(andExpr, levelGt5);

    // 3. 解释执行规则
    return orExpr.interpret(context);
    }
    }

    7. 客户端(Spring Boot 测试)

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;

    @SpringBootApplication
    public class SpringInterpreterDemoApplication {
    public static void main(String[] args) {
    // 1. 启动Spring容器
    ConfigurableApplicationContext context = SpringApplication.run(SpringInterpreterDemoApplication.class, args);
    PermissionInterpreterManager interpreterManager = context.getBean(PermissionInterpreterManager.class);

    // 2. 测试用户1:ADMIN + IT部门 → 满足规则
    User user1 = new User();
    user1.setUserId("U001");
    user1.setRole("ADMIN");
    user1.setDept("IT");
    user1.setLevel(3);
    boolean result1 = interpreterManager.checkPermission(user1);
    System.out.println("用户1是否有权限:" + result1); // true

    // 3. 测试用户2:USER + HR部门 + level=6 → 满足规则(level>5)
    User user2 = new User();
    user2.setUserId("U002");
    user2.setRole("USER");
    user2.setDept("HR");
    user2.setLevel(6);
    boolean result2 = interpreterManager.checkPermission(user2);
    System.out.println("用户2是否有权限:" + result2); // true

    // 4. 测试用户3:USER + Finance部门 + level=4 → 不满足规则
    User user3 = new User();
    user3.setUserId("U003");
    user3.setRole("USER");
    user3.setDept("Finance");
    user3.setLevel(4);
    boolean result3 = interpreterManager.checkPermission(user3);
    System.out.println("用户3是否有权限:" + result3); // false

    context.close();
    }
    }

    输出结果

    用户1是否有权限:true
    用户2是否有权限:true
    用户3是否有权限:false

    四、解释器模式的核心特点与适用场景

    优点
  • 规则可扩展:新增规则只需新增表达式类(如新增 level<3 规则,只需加 LevelLtExpression),符合开闭原则;
  • 规则可复用:相同的基础规则(如 role=ADMIN)可组合到不同的复杂规则中;
  • 规则结构化:将复杂规则拆解为小的语法单元,便于理解和维护;
  • 动态执行:可通过上下文动态修改参数(如用户信息),无需重新构建表达式树。
  • 缺点
  • 类膨胀:每个语法单元都需创建独立类,复杂规则会导致类数量爆炸;
  • 效率低下:表达式树嵌套越深,解释执行的效率越低(递归调用 + 多次上下文访问);
  • 仅适用于简单文法:复杂文法(如 SQL、正则表达式)不适合用解释器模式(应使用现成的解析器工具);
  • 调试复杂:表达式树的递归执行流程难以跟踪和调试。
  • 适用场景
  • 简单规则解析:如权限规则、过滤条件、动态配置(非复杂文法);
  • 领域特定语言(DSL):如自定义的业务规则语言(如运费计算规则、促销规则);
  • 重复执行的固定格式表达式:如计算器、公式解析器、简单的规则引擎;
  • 框架底层扩展:如 Spring EL、OGNL、MyBatis 的动态 SQL 解析(框架级应用)。
  • 五、框架中的原生应用(必须知道)

    解释器模式主要用于框架底层,业务开发中很少直接手写,但理解它能帮你看懂框架源码:

    1. Spring EL(表达式语言)
    • 文法:Spring EL 的语法规则(如 ${user.name}、#{1+2*3});
    • 抽象表达式:Expression接口;
    • 终结符 / 非终结符:LiteralExpression(字面量)、OpPlus(加法)等;
    • 解释器:SpelExpression(核心解释执行类)。
    2. MyBatis 动态 SQL
    • 文法:动态 SQL 的标签规则(<if>、<where>、<foreach>);
    • 解释器:MyBatis 的SqlSource和DynamicSqlSource(解析动态标签,生成最终 SQL)。
    3. Java 正则表达式(Pattern/Matcher)
    • 文法:正则表达式的语法规则;
    • 解释器:Pattern(编译正则表达式为语法树)、Matcher(解释执行匹配逻辑)。
    4. 计算器 / 公式引擎(如 JEP、MVEL)
    • 核心:基于解释器模式实现数学公式的解析和计算。

    六、解释器模式 vs 策略模式(易混淆点)

    维度解释器模式策略模式
    核心目的 解析并执行固定格式的规则 / 表达式 选择并执行不同的算法 / 方案
    核心结构 表达式树(终结符 + 非终结符组合) 策略接口 + 多个实现类
    扩展方式 新增表达式类(扩展语法单元) 新增策略类(扩展算法)
    执行逻辑 递归解析表达式树 直接调用策略方法
    典型场景 规则解析、公式计算、DSL 支付方式选择、排序算法、缓存策略

    总结

  • 解释器模式的核心是定义文法规则,将表达式拆解为可执行的语法单元,适用于简单规则 / 表达式的解析执行;
  • 核心角色包括抽象表达式、终结符表达式(最小单元)、非终结符表达式(组合单元)、上下文(存储状态);
  • 业务开发中,解释器模式主要用于权限规则、过滤条件等简单场景,复杂文法应使用现成的解析器工具(如 ANTLR、Spring EL);
  • 解释器模式的优点是规则可扩展、可复用,缺点是类膨胀、效率低,仅适用于简单场景。
  • 赞(0)
    未经允许不得转载:171主机测评 » 【从零入门23种设计模式15】行为型之解释器模式
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址