Java设计模式--解释器模式

本文介绍了解释器模式的目的、实现原理及其应用场景,并通过一个具体的SQL转白话文的例子详细展示了如何构建解释器模式的各个组成部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 Interpreter Pattern 解释器模式

目的:对于一个使用规定格式和语法的代码,可以建立一个解释器来解释该语言中的句子;
实现:构件语法树,定义终结符与非终结符。

1.对于一些固定文法构建一个解释句子的解释器,也就是翻译成你能懂的东西;
2.高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高;
3.解释器模式在正则表达式、XML 文档解释等领域还是得到了广泛使用。

2 实现

代码场景:将依据sql解释成白话文。
1. sql要被解释的脚本
2. 各个解释器表达式角色

2.1 代码实现

环境类角色:上下文Context类

/**
 * 全局性作用 存储一些全局性的数据
 */
public class Context {
    private String sql;
    public Context(String sql) {
        this.sql = sql;
    }
    public String getSql() {
        return sql;
    }
    public void setSql(String sql) {
        this.sql = sql;
    }
}

抽象表达式角色:AbstractExpression类

public abstract class AbstractExpression {
    // 入参为 全局性上下文
    public abstract void interpret(Context ctx);
}

非终结符表达式角色:特殊符号解释器EspecialExpression类

/**
 * 特殊符号解释器
 */
public class EspecialExpression extends AbstractExpression {
    private Map<String, String> map = new HashMap<String, String>();
    public EspecialExpression() {
        map.put("*", "所有字段");
        map.put("=", "等于");
    }
    @Override
    public void interpret(Context ctx) {
        String sql = ctx.getSql();
        if (sql.contains("=")) {
            sql = sql.replaceAll("'", "");
        }
        Iterator<String> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if (sql.contains(next)) {
                sql = sql.replace(next, map.get(next));
            }
        }
        ctx.setSql(sql);
        AbstractExpression keExp = new KeywordExpression();
        keExp.interpret(ctx);
    }
}

非终结符表达式角色:关键字号解释器KeywordExpression类

/**
 * 关键字解释器
 */
public class KeywordExpression extends AbstractExpression {
    private Map<String, String> map = new HashMap<String, String>();
    public KeywordExpression() {
        map.put("select", "查询");
        map.put("from", "从表");
        map.put("where", "中,条件是");
    }

    @Override
    public void interpret(Context ctx) {
        String sql = ctx.getSql();
        Iterator<String> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if (sql.contains(next)) {
                sql = sql.replace(next, map.get(next));
            }
        }
        ctx.setSql(sql);
        AbstractExpression keExp = new EndExpression();
        keExp.interpret(ctx);
    }

}

终结符表达式角色:EndExpression类

/**
 * 终结符解释器
 */
public class EndExpression extends AbstractExpression {

    @Override
    public void interpret(Context ctx) {
        String sql = ctx.getSql();
        sql = sql.replace(";", "");
        ctx.setSql(sql);
    }

}

2.2 涉及角色

在解释器模式结构图中包含如下几个角色:

(1)AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。

(2)TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。

(3)NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。

(4)Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。

环境类 Context 用于存储解释器之外的一些全局信息,它通常作为参数被传递到所有表达式的解释方法 interpret() 中,可以在 Context 对象中存储和访问表达式解释器的状态,向表达式解释器提供一些全局的、公共的数据,此外还可以在 Context 中增加一些所有表达式解释器都共有的功能,减轻解释器的职责。

2.3 调用

调用者:

public class Client {
    public static void main(String[] args) {
        // 要解析的sql
        String sql = "select * from students where name = 'weixx';";
        System.out.println("解析前---->" + sql);
        // 生成上下文
        Context ctx = new Context(sql);
        // 先开始特殊字符解释器
        AbstractExpression eExp = new EspecialExpression();
        eExp.interpret(ctx);
        System.out.println("解析后---->" + ctx.getSql());
    }
}

结果:

解析前---->select * from students where name = 'weixx';
解析后---->查询 所有字段 从表 students 中,条件是 name 等于 weixx

Java设计模式汇总:点击跳转
代码地址:点击跳转

参考文献:
[ 1 ] 图解设计模式/(日)结城浩著;杨文轩译。–北京:人民邮电出版社,2017.1.
[ 2 ] 维基百科 设计模式
[ 3 ] 极客学院WIKI–设计模式.
[ 4 ] 菜鸟教程–设计模式.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值