zoukankan      html  css  js  c++  java
  • 行为型模式:解释器模式

    原文首发:
    行为型模式:解释器模式

    鲨鱼

    十一大行为型模式之十:解释器模式。

    简介

    姓名 :解释器模式
    英文名 :Interpreter Pattern
    价值观 :不懂解释到你懂​
    个人介绍
    Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
    给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
    (来自《设计模式之禅》)

    你要的故事

    解释器顾名思义就是对 2 个不同的表达方式进行转换,让本来不懂的内容解释成看得懂的。比如翻译官就是解释器,把英文翻译成中文,让我们明白外国人说什么。咱们工作中也有很多类似的场景,开发系统避免不了使用数据库,数据库有特定的语法,我们称为 SQL (Structured Query Language),而我们系统开发语言和 SQL 的语法不一样,这中间就需要做一层转换,像把 Java 语言中的 userDao.save(user) 变成 insert into user (name,age) values ('小明', 18),这一层转换也可以称为解释器。很多框架实现了这个功能,比如 Hibernate,我们称这些框架为 ORM

    今天,我们就来简单的实现 SQL 拼接解释器,通过参数组装成我们要的 SQL 语句。好多开发同学都吐槽工作天天在 CRUD,也就是只干增删改查的活,对于 SQL 我们经常用的也就是这 4 种语法:insert 语句、delete 语句、update 语句、select 语句。这 4 种语法各有不同,也即需要不同的解释器去解析。利用今天要讲的解释器模式,我们来实现一番。

    解释器模式中,会有一个上下文类,这个类用于给解释器传递参数。这里我们 SQL 解释器需要的参数分别是

    1. tableName :数据库名
    2. params :修改时更新后的数据
    3. wheres :where 语句后的条件
    class Context {
        private String tableName;
        private Map<String, Object> params = new HashMap<>();
        private Map<String, Object> wheres = new HashMap<>();
    
        public String getTableName() {
            return tableName;
        }
    
        public void setTableName(String tableName) {
            this.tableName = tableName;
        }
    
        public Map<String, Object> getParams() {
            return params;
        }
    
        public void setParams(Map<String, Object> params) {
            this.params = params;
        }
    
        public Map<String, Object> getWheres() {
            return wheres;
        }
    
        public void setWheres(Map<String, Object> wheres) {
            this.wheres = wheres;
        }
    }
    

    解释器主角来了,定义 SQL 解释器抽象类,它有一个抽象方法 interpret,通过这个方法来把 context 中的参数解释成对应的 SQL 语句。

    /**
     * SQL 解释器
     */
    abstract class SQLExpression {
    
        public abstract String interpret(Context context);
    
    }
    

    我们上面说了 SQL 语句用的比较多的就是 4 种,每一种其实就是一个解释器,因为语法不一样,解释的逻辑也就不一样,我们就利用 SQLExpression 解释器抽象类,来实现 4 个具体的 SQL 解释器,分别如下:

    Insert SQL 解释器代码实现:

    /**
     * Insert SQL 解释器
     */
    class InsertSQLExpression extends SQLExpression {
    
        @Override
        public String interpret(Context context) {
            StringBuilder insert = new StringBuilder();
            insert.append("insert into ")
                    .append(context.getTableName());
    
            // 解析 key value
            StringBuilder keys = new StringBuilder();
            StringBuilder values = new StringBuilder();
            keys.append("(");
            values.append("(");
            for (String key : context.getParams().keySet()) {
                keys.append(key).append(",");
                values.append("'").append(context.getParams().get(key)).append("',");
            }
            keys = keys.replace(keys.length() - 1, keys.length(), ")");
            values = values.replace(values.length() - 1, values.length(), ")");
    
            // 拼接 keys values
            insert.append(keys)
                    .append(" values ")
                    .append(values);
    
            System.out.println("Insert SQL : " + insert.toString());
            return insert.toString();
        }
    }
    

    Update SQL 解释器代码实现:

    /**
     * Update SQL 解释器
     */
    class UpdateSQLExpression extends SQLExpression {
    
        @Override
        public String interpret(Context context) {
            StringBuilder update = new StringBuilder();
            update.append("update ")
                    .append(context.getTableName())
                    .append(" set ");
    
            StringBuilder values = new StringBuilder();
            for (String key : context.getParams().keySet()) {
                values.append(key)
                        .append(" = '")
                        .append(context.getParams().get(key))
                        .append("',");
            }
    
            StringBuilder wheres = new StringBuilder();
            wheres.append(" 1 = 1 ");
            for (String key : context.getWheres().keySet()) {
                wheres.append(" and ")
                        .append(key)
                        .append(" = '")
                        .append(context.getWheres().get(key))
                        .append("'");
            }
    
            update.append(values.substring(0, values.length() - 1))
                    .append(" where ")
                    .append(wheres);
    
            System.out.println("Update SQL : " + update.toString());
            return update.toString();
        }
    }
    

    Select SQL 解释器代码实现:

    /**
     * Select SQL 解释器
     */
    class SelectSQLExpression extends SQLExpression {
    
        @Override
        public String interpret(Context context) {
            StringBuilder select = new StringBuilder();
            select.append("select * from ")
                    .append(context.getTableName())
                    .append(" where ")
                    .append(" 1 = 1 ");
            for (String key : context.getWheres().keySet()) {
                select.append(" and ")
                        .append(key)
                        .append(" = '")
                        .append(context.getWheres().get(key))
                        .append("'");
            }
            System.out.println("Select SQL : " + select.toString());
            return select.toString();
        }
    }
    

    Delete SQL 解释器代码实现

    /**
     * Delete SQL 解释器
     */
    class DeleteSQLExpression extends SQLExpression {
    
        @Override
        public String interpret(Context context) {
            StringBuilder delete = new StringBuilder();
            delete.append("delete from ")
                    .append(context.getTableName())
                    .append(" where ")
                    .append(" 1 = 1");
            for (String key : context.getWheres().keySet()) {
                delete.append(" and ")
                        .append(key)
                        .append(" = '")
                        .append(context.getWheres().get(key))
                        .append("'");
            }
            System.out.println("Delete SQL : " + delete.toString());
    
            return delete.toString();
        }
    }
    

    测试代码

    public class InterpreterTest {
        public static void main(String[] args) {
            Context context = new Context();
            context.setTableName("user");
    
            // Insert SQL
            Map<String, Object> params = new HashMap<>();
            params.put("name", "小明");
            params.put("job", "Java 工程师");
            context.setParams(params);
            SQLExpression sqlExpression = new InsertSQLExpression();
            String sql = sqlExpression.interpret(context);
    
            // Delete SQL
            Map<String, Object> wheres = new HashMap<>();
            wheres.put("name", "小明");
            context.setParams(null);
            context.setWheres(wheres);
            sqlExpression = new DeleteSQLExpression();
            sql = sqlExpression.interpret(context);
    
            // Update SQL
            params = new HashMap<>();
            params.put("job", "Java 高级工程师");
            wheres = new HashMap<>();
            wheres.put("name", "小明");
            context.setParams(params);
            context.setWheres(wheres);
            sqlExpression = new UpdateSQLExpression();
            sql = sqlExpression.interpret(context);
    
            // Select SQL
            wheres = new HashMap<>();
            wheres.put("name", "小明");
            context.setParams(null);
            context.setWheres(wheres);
            sqlExpression = new SelectSQLExpression();
            sql = sqlExpression.interpret(context);
        }
    
    }
    
    打印结果:
    
    Insert SQL : insert into user(name,job) values ('小明','Java 工程师')
    Delete SQL : delete from user where  1 = 1 and name = '小明'
    Update SQL : update user set job = 'Java 高级工程师' where  1 = 1  and name = '小明'
    Select SQL : select * from user where  1 = 1  and name = '小明'
    

    上面实现了整个解释器模式的代码,其实咱们在开发中,SQL 解析没有这么去实现,更多是用一个工具类把上面的各个 SQL 解释器的逻辑代码分别实现在不同方法中,如下代码所示。因为咱们可以预见的就这 4 种语法类型,基本上不用什么扩展,用一个工具类就足够了。

    class SQLUtil {
    
        public static String insert(String tableName, Map<String, Object> params) {
            StringBuilder insert = new StringBuilder();
            insert.append("insert into ")
                    .append(tableName);
    
            // 解析 key value
            StringBuilder keys = new StringBuilder();
            StringBuilder values = new StringBuilder();
            keys.append("(");
            values.append("(");
            for (String key : params.keySet()) {
                keys.append(key).append(",");
                values.append("'").append(params.get(key)).append("',");
            }
            keys = keys.replace(keys.length() - 1, keys.length(), ")");
            values = values.replace(values.length() - 1, values.length(), ")");
    
            // 拼接 keys values
            insert.append(keys)
                    .append(" values ")
                    .append(values);
    
            System.out.println("Insert SQL : " + insert.toString());
            return insert.toString();
        }
    
        public static String update(String tableName, Map<String, Object> params, Map<String, Object> wheres) {
            StringBuilder update = new StringBuilder();
            update.append("update ")
                    .append(tableName)
                    .append(" set ");
    
            StringBuilder values = new StringBuilder();
            for (String key : params.keySet()) {
                values.append(key)
                        .append(" = '")
                        .append(params.get(key))
                        .append("',");
            }
    
            StringBuilder wheresStr = new StringBuilder();
            wheresStr.append(" 1 = 1 ");
            for (String key : wheres.keySet()) {
                wheresStr.append(" and ")
                        .append(key)
                        .append(" = '")
                        .append(wheres.get(key))
                        .append("'");
            }
    
            update.append(values.substring(0, values.length() - 1))
                    .append(" where ")
                    .append(wheresStr);
    
            System.out.println("Update SQL : " + update.toString());
            return update.toString();
        }
    
        public static String select(String tableName, Map<String, Object> wheres) {
            StringBuilder select = new StringBuilder();
            select.append("select * from ")
                    .append(tableName)
                    .append(" where ")
                    .append(" 1 = 1 ");
            for (String key : wheres.keySet()) {
                select.append(" and ")
                        .append(key)
                        .append(" = '")
                        .append(wheres.get(key))
                        .append("'");
            }
            System.out.println("Select SQL : " + select.toString());
            return select.toString();
        }
    
        public static String delete(String tableName, Map<String, Object> wheres) {
            StringBuilder delete = new StringBuilder();
            delete.append("delete from ")
                    .append(tableName)
                    .append(" where ")
                    .append(" 1 = 1");
            for (String key : wheres.keySet()) {
                delete.append(" and ")
                        .append(key)
                        .append(" = '")
                        .append(wheres.get(key))
                        .append("'");
            }
            System.out.println("Delete SQL : " + delete.toString());
    
            return delete.toString();
        }
    }
    

    总结

    上面用解释器模式实现了 SQL 解释器,然后又指明了实际上咱们开发中大多数是直接一个 SQLUtil 工具类就搞定,并不是说解释器模式没用,想表达的观点是:解释器在工作中很少使用,工作中我们一般遵循的是能用就好策略,满足当前需求,加上一些易扩展性就足够了。解释器模式有比较大的扩展性,就如上面,再加上个建表语句 create table 只需要加一个 CreateTableSQLExpression 就可以轻松实现,不用去改动其他解释器代码。今天的解释器就到讲到这。觉得不错点个赞鼓励鼓励一下。

    推荐阅读

    行为型模式:备忘录模式

    行为型模式:观察者模式

    行为型模式:迭代器模式

  • 相关阅读:
    今天碰到的angular 中的一个小坑
    mvc 防止客服端多次提交
    自定义通用Distinct去除重复数据的2中方式
    Sql 字符串操作类COALESCE
    SQL Server 性能优化
    Visual Studio Tip: Get Public Key Token for a Strong Named Assembly
    C#发送邮件
    Web打印组件jatoolsPrinter(转载)
    SQL SERVER 2005 同步复制技术(转)
    [Asp.net]常见word,excel,ppt,pdf在线预览方案(转)
  • 原文地址:https://www.cnblogs.com/liebrother/p/10708603.html
Copyright © 2011-2022 走看看