【Java开发】设计模式 12:解释器模式

1 解释器模式介绍 

解释器模式是一种行为型设计模式,它提供了一种方法来解释语言、表达式或符号。

在该模式中,定义了一个表达式接口,并实现了对应的表达式类,这些类可以解释不同的符号组成的表达式,从而实现对语言的解释。

📌 场景

这种模式常常被用在编译器、解释器和正则表达式库中。该模式的核心思想是将一个复杂的问题分解成许多简单的问题,并将这些问题之间的关系表示为一种语法规则。

📌 优点

  1. 灵活性好:解释器模式能够灵活地处理复杂的或变化的语法规则,因为语法规则都是由解释器来进行解释和处理的。
  2. 易于修改和扩展:由于解释器模式中的文法以类的形式存在,所以增加新的文法规则和解释器相对容易。

📌 缺点

  1. 执行效率较低:因为使用解释器模式需要对文法规则进行解析和执行,而这个过程是比较耗时的,所以解释器模式的执行效率较低。
  2. 增加系统复杂性:因为解释器模式中的文法规则以类的形式存在,所以随着文法规则的增加,类的数量也会随之增加,这会增加系统的复杂性。
  3. 可维护性较差:由于解释器模式中的文法规则以类的形式存在,如果系统中存在大量的文法规则,那么系统的维护难度也会相应增加。

📌 注意

解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。如果碰到对表达式的解释,在 Java 中可以用 Expression4J 或 Jep 等来设计。

📌 四大角色

  • 抽象表达式(Expression) :负责定义解释方法 interpret, 交由子类进行具体解释。
  • 终结符表达式(Terminal Expression) :实现文法中与终结符有关的解释操作。文法中的每一个终结符都有一个具体终结表达式与之相对应,比如公式 R = R1 + R2,R1 和 R2 就是终结符,对应的解析 R1 和 R2 的解释器就是终结符表达式。通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。
  • 非终结符表达式(Nonterminal Expression):实现文法中与非终结符有关的解释操作。文法中的每条规则都对应于一个非终结符表达式。非终结符表达式一般是文法中的运算符或者其他关键字,比如公式 R = R1 + R2 中, + 就是非终结符,解析它的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
  • 上下文环境(Context) :包含解释器之外的全局信息。它的任务一般是用来存放文法中各个终结符所对应的具体值,比如 R = R1 + R2,给 R1 赋值 100,给 R2 赋值 200,这些信息需要存放到环境中。

2 解释器模式实现

以根据乘客年龄和身高来判断乘坐公交车是否免费为例:

📌 1.定义乘客

/**
 * 乘客
 */
@Data
@AllArgsConstructor
public class Passenger {
    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 身高
     */
    private Double height;
}

📌 2.定义表达式

/**
 * 表达式
 */
public interface Expression {
    /**
     * 解释年龄
     * @param age 年龄
     * @return 解释结果
     */
    boolean interpret(int age);

    /**
     * 解释身高
     * @param height 身高
     * @return 解释结果
     */
    boolean interpret(double height);
}

📌 3.定义比较器(枚举)

/**
 * 比较器
 */
public enum Compare {
    /**
     * 较大
     */
    GT,
    /**
     * 相等
     */
    EQ,
    /**
     * 较小
     */
    LT
}

📌 4.定义终结符表达式

/**
 * 终结符表达式
 */
public class TerminalExpression implements Expression {
    /**
     * 年龄
     */
    private Integer age;

    /**
     * 身高
     */
    private Double height;

    /**
     * 比较器
     */
    private final Compare compare;

    /**
     * 构造年龄比较
     * @param age 年龄
     * @param compare 比较器
     */
    public TerminalExpression(int age, Compare compare) {
        this.age = age;
        this.compare = compare;
    }

    /**
     * 构造身高比较
     * @param height 身高
     * @param compare 比较器
     */
    public TerminalExpression(double height, Compare compare) {
        this.height = height;
        this.compare = compare;
    }

    @Override
    public boolean interpret(int age) {
        // 比较年龄大小
        switch (compare) {
            // 较大
            case GT:
                return age > this.age;
            // 相等
            case EQ:
                return age == this.age;
            // 较小
            case LT:
                return age < this.age;
            default:
                return false;
        }
    }

    @Override
    public boolean interpret(double height) {
        // 比较身高大小
        switch (compare) {
            // 较大
            case GT:
                return height > this.height;
            // 相等
            case EQ:
                return height == this.height;
            // 较小
            case LT:
                return height < this.height;
            default:
                return false;
        }
    }
}

📌 5.定义非终结符表达式

①与表达式:

/**
 * 与表达式
 */
public class AndExpression implements Expression {
    /**
     * 表达式1
     */
    private Expression expression1;
    /**
     * 表达式2
     */
    private Expression expression2;
    /**
     * 构造表达式
     * @param expression1 表达式1
     * @param expression2 表达式2
     */
    public AndExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }
    @Override
    public boolean interpret(int age) {
        return this.expression1.interpret(age) && this.expression2.interpret(age);
    }
    @Override
    public boolean interpret(double height) {
        return this.expression1.interpret(height) && this.expression2.interpret(height);
    }
}

②或表达式:

/**
 * 或表达式
 */
public class OrExpression implements Expression {
    /**
     * 表达式1
     */
    private Expression expression1;

    /**
     * 表达式2
     */
    private Expression expression2;

    /**
     * 构造表达式
     * @param expression1 表达式1
     * @param expression2 表达式2
     */
    public OrExpression(Expression expression1, Expression expression2) {
        this.expression1 = expression1;
        this.expression2 = expression2;
    }
    @Override
    public boolean interpret(int age) {
        return this.expression1.interpret(age) || this.expression2.interpret(age);
    }
    @Override
    public boolean interpret(double height) {
        return this.expression1.interpret(height) || this.expression2.interpret(height);
    }
}

📌 6.定义免费标准

/**
 * 免费标准
 */
public class Free {
    /**
     * 年龄表达式
     */
    private Expression ageExpression;

    /**
     * 身高表达式
     */
    private Expression heightExpression;

    /**
     * 构造免费情况
     * @param age 年龄
     * @param height 身高
     */
    public Free(int age, double height) {
        // 大于等于设定年龄
        Expression expression1 = new TerminalExpression(age, Compare.GT);
        Expression expression2 = new TerminalExpression(age, Compare.EQ);
        ageExpression = new OrExpression(expression1, expression2);
        // 小于等于设定身高
        expression1 = new TerminalExpression(height, Compare.LT);
        expression2 = new TerminalExpression(height, Compare.EQ);
        heightExpression = new OrExpression(expression1, expression2);
    }

    /**
     * 结果
     * @param age 年龄
     * @param height 身高
     * @return 判定结果
     */
    public boolean adjust(int age, double height) {
        return ageExpression.interpret(age) || heightExpression.interpret(height);
    }
}

📌 7.调用

// 定义乘客集合
List<Passenger> list = new ArrayList<>();
Passenger p1 = new Passenger("张三", 65, 170.0);
Passenger p2 = new Passenger("李四", 10, 130.0);
Passenger p3 = new Passenger("王五", 50, 170.0);
list.add(p1);
list.add(p2);
list.add(p3);

list.forEach(p->{
    // 定义免费标准
    Free free = new Free(65, 130);
    // 满足条件则免费
    if (free.adjust(p.getAge(), p.getHeight())) {
        System.out.println(p.getName() + ":免费");
    }// 不满足条件则正常收费
    else {
        System.out.println(p.getName() + ":刷卡或投币");
    }
});

控制台输出:

可以看到,这里按照预期输出了结果,实现了根据年龄和身高自动判断是否免费的功能。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹煜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值