mybatis框架之装饰模式
学习开源框架源码,除了储备点知识以便于与面试官互相忽略之外,我想最重要的还是去学习大神如何写代码,如何做到职责单一,如何做到可扩展等。。。
本篇,试着总结一下mybatis在缓存模块使用到的装饰模式。
或许一说到装饰模式就会扯到装饰模式四种角色,但我觉得这些都是扯蛋,没必需照本宣科,我觉得myabtis框架也不是完全的装饰模式,或许可以说是变异版本。
其实,我觉得大多的设计模式无非就是面向接口编程与接口引用的组合罢了!
下面看看mybatis框架的cache模块是如何使用装饰模式的
1. 首先,定义了一个cache接口,具体的功能都在接口中说明了,主要是putObject 和getObject
public interface Cache {
String getId();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
int getSize();
default ReadWriteLock getReadWriteLock() {
return null;
}
}
2. 然后,再看一下Cache的继承体系

清一色的java类,并没有啥抽象类或者接口,这就与教科书中的装饰模式有点区别了。。。。
3. 每一个Cache实现类都持有一个Cache引用
看下LoggingCache类的源代码
public class LoggingCache implements Cache {
private final Log log;
private final Cache delegate;
protected int requests = 0;
protected int hits = 0;
public LoggingCache(Cache delegate) {
this.delegate = delegate;
this.log = LogFactory.getLog(getId());
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public int getSize() {
return delegate.getSize();
}
@Override
public void putObject(Object key, Object object) {
delegate.putObject(key, object);
}
@Override
public Object getObject(Object key) {
requests++;
final Object value = delegate.getObject(key);
if (value != null) {
hits++;
}
if (log.isDebugEnabled()) {
log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio());
}
return value;
}
@Override
public Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public void clear() {
delegate.clear();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
private double getHitRatio() {
return (double) hits / (double) requests;
}
}
LoggingCache类的构造器传入了一个Cache实例delegate, 再看getObject方法

这么一看,貌似很符合装饰模式的精神内核,但是并没有照搬装饰模式的套路。而且,,,这似乎与责任链的套路也很像。。。。
假设LoggingCache的构造器入参是FifoCache, 而FifoCache的构造器入参又是RedsiCache, 那么在调用LoggingCache#getObject方法时就会形成一条链:
LoggingCache#getObject()-----------> FifoCache#getObject()--------------------> RedisCache#getObject() (这难道不能算责任链嘛,当然与真正的责任又有些差别),
而且这条调用链中,LoggingCache#getObject ()进行前、后功能增强,而FifoCache#getObject()-进行了前置功能增强, 当然RedisCache#getObject()仅是查询redis库。
mybatis框架就是这样操作的,这条调用链具体怎么组合,完全看Cache的Caller是如何去构造链节点的关系,使用得相当灵活,我觉得它相当于: 责任链+装饰。
而实现这种套路的技术就是Cache的所有实现类中都持有了一个Cache对象的引用。 注意是Cache对象,而非Cache的具体实现对象!
或许这就是面向接口编程吧!
在以后工作中,能用就尽可能用吧,切记!
mybatis框架之装饰模式的更多相关文章
- mybatis框架之动态代理
坦白讲,动态代理在日常工作中真没怎么用过,也少见别人用过,网上见过不少示例,但总觉与装饰模式差别不大,都是对功能的增强,什么前置后置,其实也就那么回事,至于面试中经常被问的mybatis框架mappe ...
- Mybatis框架的多对一关联关系(六)
一.一对多的关联映射 一对多关联查询多表数据 1接口 public interface IDeptDAO { //根据部门编号查询该部门单个查询 public Emp getEmpById(Integ ...
- Spring+SpringMvc+Mybatis框架集成搭建教程
一.背景 最近有很多同学由于没有过SSM(Spring+SpringMvc+Mybatis , 以下简称SSM)框架的搭建的经历,所以在自己搭建SSM框架集成的时候,出现了这样或者那样的问题,很是苦恼 ...
- Mybatis框架中实现双向一对多关系映射
学习过Hibernate框架的伙伴们很容易就能简单的配置各种映射关系(Hibernate框架的映射关系在我的blogs中也有详细的讲解),但是在Mybatis框架中我们又如何去实现 一对多的关系映射呢 ...
- Hibernate框架与Mybatis框架的对比
学习了Hibernate和Mybatis,但是一直不太清楚他们两者的区别的联系,今天在网上翻了翻,就做了一下总结,希望对大家有帮助! 原文:http://blog.csdn.net/firejuly/ ...
- 初识Mybatis框架,实现增删改查等操作(动态拼接和动态修改)
此第一次接触Mybatis框架确实是有点不适应,特别是刚从Hibernate框架转转型过来,那么为什么要使用Mybatis框架,Mybatis框架和Hibernate框架又有什么异同呢? 这个问题在我 ...
- Spring+MyBatis框架中sql语句的书写,数据集的传递以及多表关联查询
在很多Java EE项目中,Spring+MyBatis框架经常被用到,项目搭建在这里不再赘述,现在要将的是如何在项目中书写,增删改查的语句,如何操作数据库,以及后台如何获取数据,如何进行关联查询,以 ...
- SSM框架-----------SpringMVC+Spring+Mybatis框架整合详细教程
1.基本概念 1.1.Spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One ...
- Spring3.0 与 MyBatis框架 整合小实例
本文将在Eclipse开发环境下,采用Spring MVC + Spring + MyBatis + Maven + Log4J 框架搭建一个Java web 项目. 1. 环境准备: 1.1 创建数 ...
随机推荐
- postman使用动态token发post请求小结
最近使用postman做接口测试,感觉挺好用的. 测试中,每次post请求都要携带一个token,token是通过get请求得来的,动态变化的,并且token有有效期的限制.为了避免重复获取token ...
- JS-格式化json
一 使用原生 JSON.stringify 实现 <textarea name="" id="myTA" cols="30" rows ...
- Oracle创建dblink进行跨数据库操作
创建dblink:create public database link link_to_test connect to 用户名 IDENTIFIED by "密码大写" usin ...
- Git错误总结
1.error: failed to push some refs to ‘git@github.com:XXXX/XXXX‘ hint: Updates were rejected because ...
- Linux运维工程师前景
什么是Linux运维 如果我们是一辆高速行驶在高速公路上的汽车,那运维工程师就是司机兼维修工,这个司机可不简单,有时需要在高速行驶过程中更换轮胎.并根据道路情况换档位.当汽车速度越来越快时,汽车本身不 ...
- rpm --qf 命令
1. 环境准备: sudo apt-get install rpm (Ubuntu系统) wget ftp://rpmfind.net/linux/fedora-secondary/developme ...
- JS创建表格完整
<!DOCTYPE> <html> <head> <meta charset=utf-8 /> <title>动态表格</title& ...
- jQury+Ajax与C#后台交换数据
-------------------------------------------jQury+Ajax调用后台方法----------------------------------------- ...
- 牛客练习赛27-----C.水图(DFS求最长路径)
传送门 来源:牛客网题目描述:小w不会离散数学,所以她van的图论游戏是送分的小w有一张n个点n-1条边的无向联通图,每个点编号为1~n,每条边都有一个长度小w现在在点x上她想知道从点x出发经过每个点 ...
- vector中数据释放崩溃问题
struct LINE { char securityID[32]; /*!< 证券代码 */ int64_t dateTime; /*!< 日期时间(日期变化)YYYYMMDDhhmms ...