行为型模式:解释器模式
原文首发: 行为型模式:解释器模式
十一大行为型模式之十:解释器模式。
简介
姓名 :解释器模式
英文名 :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 就可以轻松实现,不用去改动其他解释器代码。今天的解释器就到讲到这。觉得不错点个赞鼓励鼓励一下。
推荐阅读
设计模式系列文章持续更新中,欢迎关注公众号 LieBrother,一起交流学习。
关注公众号
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
死磕 java集合之HashSet源码分析
问题 (1)集合(Collection)和集合(Set)有什么区别? (2)HashSet怎么保证添加元素不重复? (3)HashSet是否允许null元素? (4)HashSet是有序的吗? (5)HashSet是同步的吗? (6)什么是fail-fast? 简介 集合,这个概念有点模糊。 广义上来讲,java中的集合是指java.util包下面的容器类,包括和Collection及Map相关的所有类。 中义上来讲,我们一般说集合特指java集合中的Collection相关的类,不包含Map相关的类。 狭义上来讲,数学上的集合是指不包含重复元素的容器,即集合中不存在两个相同的元素,在java里面对应Set。 具体怎么来理解还是要看上下文环境。 比如,面试别人让你说下java中的集合,这时候肯定是广义上的。 再比如,下面我们讲的把另一个集合中的元素全部添加到Set中,这时候就是中义上的。 HashSet是Set的一种实现方式,底层主要使用HashMap来确保元素不重复。 源码分析 属性 // 内部使用HashMap private transient HashMap<E,Obje...
-
下一篇
对于MySQL你必须要了解的锁知识
一、前言 MySQL 的锁按照范围可以分为全局锁、表锁、行锁,其中行锁是由数据库引擎实现的,并不是所有的引擎都提供行锁,MyISAM 就不支持行锁,所以文章介绍行锁会以InnoDB引擎为例来介绍行锁。 二、全局锁 MySQL 提供全局锁来对整个数据库实例加锁。 语法: FLUSH TABLES WITH READ LOCK 这条语句一般都是用来备份的,当执行这条语句后,数据库所有打开的表都会被关闭,并且使用全局读锁锁定数据库的所有表,同时,其他线程的更新语句(增删改),数据定义语句(建表,修改表结构)和更新类的事务提交都会被阻塞。 在mysql 8.0 以后,对于备份,mysql可以直接使用备份锁。 语句: LOCK INSTANCE FOR BACKUP UNLOCK INSTANCE 这个锁的作用范围更广,这个锁会阻止文件的创建,重命名,删除,包括 REPAIR TABLE TRUNCATE TABLE, OPTIMIZE TABLE操作以及账户的管理都会被阻塞。当然这些操作对于内存临时表来说是可以执行的,为什么内存表不受这些限制呢?因为内存表不需要备份,所以也就没必要满足这些条件...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL数据库中FOR UPDATE的使用
- Docker容器配置,解决镜像无法拉取问题
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS8编译安装MySQL8.0.19
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,CentOS8安装Elasticsearch6.8.6



微信收款码
支付宝收款码