装饰器设计模式
定义
装饰器模式,在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
装饰器用来包装原有的类,在对使用者透明的情况下做功能的增强,比如java中的BufferedInputStream
可以对其包装的InputStream
做增强,从而提供缓冲功能。
使用场景
MyBatis里的缓存设计,就是装饰器模式的典型应用。
首先,MyBatis执行器是MyBatis调度的核心,它负责SQL语句的生成和执行。
在创建SqlSession
的时候,会创建这个执行器,默认的执行器是SimpleExecutor
。
但是为了给执行器增加缓存的职责,就变成了在SimpleExecutor
上一层添加了CachingExecutor
。
在CachingExecutor
中的实际操作还是委托给SimpleExecutor
去执行,只是在执行前后增加了缓存的操作。
首先,来看看它的装饰过程。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
//默认的执行器
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
//使用缓存执行器来装饰
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
当SqlSession执行方法的时候,则会先调用到CachingExecutor
,来看查询方法。
public class CachingExecutor implements Executor {
@Override
public <E> List<E> query()throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
}
这里的代码,如果开启了缓存,则先从缓存中获取结果。如果没有开启缓存或者缓存中没有结果,则再调用SimpleExecutor
执行器去数据库中查询。
希望对原有类的功能做增强,但又不希望增加过多子类时,可以使用装饰器模式来达到同样的效果。
实践经验
总结
使用装饰器模式做了功能的增强,对使用者来说只需要做简单的组合就能继续使用原功能。