当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 行为型模式:解释器模式

行为型模式:解释器模式

2019年04月16日  | 移动技术网IT编程  | 我要评论

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

鲨鱼

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

简介

姓名 :解释器模式
英文名 :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 就可以轻松实现,不用去改动其他解释器代码。今天的解释器就到讲到这。觉得不错点个赞鼓励鼓励一下。

推荐阅读

行为型模式:备忘录模式

行为型模式:观察者模式

行为型模式:迭代器模式

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网