行爲型模式:解釋器模式

原文首發:
行爲型模式:解釋器模式sql

鯊魚

十一大行爲型模式之十:解釋器模式。數據庫

簡介

姓名 :解釋器模式
英文名 :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 種語法各有不一樣,也即須要不一樣的解釋器去解析。利用今天要講的解釋器模式,咱們來實現一番。app

解釋器模式中,會有一個上下文類,這個類用於給解釋器傳遞參數。這裏咱們 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 語句。ide

/**
 * 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 解釋器代碼實現:ui

/**
 * 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 就能夠輕鬆實現,不用去改動其餘解釋器代碼。今天的解釋器就到講到這。以爲不錯點個贊鼓勵鼓勵一下。

推薦閱讀

行爲型模式:備忘錄模式

行爲型模式:觀察者模式

行爲型模式:迭代器模式

相關文章
相關標籤/搜索