原文首發: "行為型模式:解釋器模式" 十一大行為型模式之十:解釋器模式。 簡介 姓名 :解釋器模式 英文名 :Interpreter Pattern 價值觀 :不懂解釋到你懂 個人介紹 : Given a language, define a representation for its gra ...
原文首發:
行為型模式:解釋器模式
十一大行為型模式之十:解釋器模式。
簡介
姓名 :解釋器模式
英文名 :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 解釋器需要的參數分別是
- tableName :資料庫名
- params :修改時更新後的數據
- 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
就可以輕鬆實現,不用去改動其他解釋器代碼。今天的解釋器就到講到這。覺得不錯點個贊鼓勵鼓勵一下。
推薦閱讀