装饰器设计模式
定义
装饰器模式,在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
装饰器用来包装原有的类,在对使用者透明的情况下做功能的增强,比如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 {@Overridepublic <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
执行器去数据库中查询。
希望对原有类的功能做增强,但又不希望增加过多子类时,可以使用装饰器模式来达到同样的效果。
实践经验
总结
使用装饰器模式做了功能的增强,对使用者来说只需要做简单的组合就能继续使用原功能。