原文首發:
行爲型模式:解釋器模式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 種語法各有不一樣,也即須要不一樣的解釋器去解析。利用今天要講的解釋器模式,咱們來實現一番。數組
解釋器模式中,會有一個上下文類,這個類用於給解釋器傳遞參數。這裏咱們 SQL 解釋器須要的參數分別是app
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 解釋器,分別以下:ide
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
就能夠輕鬆實現,不用去改動其餘解釋器代碼。今天的解釋器就到講到這。以爲不錯點個贊鼓勵鼓勵一下。
推薦閱讀
設計模式系列文章持續更新中,歡迎關注公衆號 LieBrother,一塊兒交流學習。