jQuery火箭图标返回顶部代码

Mybatis设计模式

创建型

建造者模式,工厂模式

我们在单独Mybatis框架执行SQL语句的时候,需要获得SqlSession实例来直接执行已映射的 SQL 语句,在获得SqlSession实例的过程中,就使用了建造者模式和工厂模式。我们来看看一下调用过程:

这里的Resource类使用了简单工厂模式,通过xml配置文件获得输入流,不过今天我想重点介绍一下SqlSessionFactoryBuilder类和SqlSessionFactory接口,他们分别使用了建造者模式和工厂模式。传统的建造者模式有两个重要的角色:建造者和指导者,将责任进行分割,可在实际的使用中往往只有一个建造者类调用重载的build()方法创建对象,建造者模式解决的问题是某些参数可能是可选的,避免被迫定义所有参数创建对象。DefaultSqlSessionFactory类使用了工厂模式,通过不同的配置产生不同的SqlSession类执行SQL语句。

单例模式

ErrorContext是MyBatis中用于记录线程范围内执行环境错误信息的单例对象。每个线程在执行数据库操作时,都会有一个对应的ErrorContext对象来记录当前执行的上下文信息和错误信息。ErrorContext对象被存储进ThreadLocal被设计成线程范围内的单例,这意味着每个线程只会有一个ErrorContext对象。在多线程环境下,使用单例模式可以保证每个线程都能够独立地记录自己的执行环境错误信息,能够避免了线程之间信息错误传递。

ErrorContext部分源码如下:

复制代码
 1 // 将自身存储进ThreadLocal,从而进行线程间的隔离
 2 private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>();
 3 
 4 private ErrorContext() {
 5 }
 6 /**
 7  * 从ThreadLocal取出已经实例化的ErrorContext,或者实例化一个ErrorContext放入ThreadLocal
 8  * @return ErrorContext实例
 9  */
10 public static ErrorContext instance() {
11   ErrorContext context = LOCAL.get();
12   if (context == null) {
13     context = new ErrorContext();
14     LOCAL.set(context);
15   }
16   return context;
17 }
复制代码

结构型

适配器模式

适配器模式可以解决兼容性问题,在Mybatsi的logging包中,有一个Log接口,该接口定义了MyBatis直接使用的日志方法,即目标类。

复制代码
1 public interface Log {
2     boolean isDebugEnabled();
3     boolean isTraceEnabled();
4     void error(String var1, Throwable var2);
5     void error(String var1);
6     void debug(String var1);
7     void trace(String var1);
8     void warn(String var1);
9 }
复制代码

实现该接口的适配器类有多个,比如对于Log4jImpl的实现来说,该实现持有了org.apache.log4j.Logger的实例,然后所有的日志方法,均委托该实例来实现。

复制代码
 1 import org.apache.ibatis.logging.Log;
 2 import org.apache.log4j.Level;
 3 import org.apache.log4j.Logger;
 4 public class Log4jImpl implements Log {
 5     private static final String FQCN = Log4jImpl.class.getName();
 6     private final Logger log;
 7     public Log4jImpl(String clazz) {
 8         this.log = Logger.getLogger(clazz);
 9     }
10     public boolean isDebugEnabled() {
11         return this.log.isDebugEnabled();
12     }
13     public boolean isTraceEnabled() {
14         return this.log.isTraceEnabled();
15     }
16     public void error(String s, Throwable e) {
17         this.log.log(FQCN, Level.ERROR, s, e);
18     }
19     public void error(String s) {
20         this.log.log(FQCN, Level.ERROR, s, (Throwable)null);
21     }
22     public void debug(String s) {
23         this.log.log(FQCN, Level.DEBUG, s, (Throwable)null);
24     }
25     public void trace(String s) {
26         this.log.log(FQCN, Level.TRACE, s, (Throwable)null);
27     }
28     public void warn(String s) {
29         this.log.log(FQCN, Level.WARN, s, (Throwable)null);
30     }
31 }
复制代码

装饰者模式

装饰器模式它允许在不修改现有代码的情况下,通过将对象包装在装饰器对象中来动态地添加新的行为和功能。在MyBatis中,缓存的功能由Cache接口(抽象构件)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(具体构建)实现,然后通过一系列的装饰器来对PerpetualCache进行缓存策略的增强。

  • 抽象组件:Cache 接口,定义了缓存接口的基本方法。

  • 具体组件:PerpetualCache 类,实现了 Cache 接口,提供了缓存的基本实现。

  • 具体装饰者:LruCache 类、ScheduledCache 类、LoggingCache 类等,实现了 Cache 类并实现了其抽象方法,提供了具体的缓存增强功能。

复制代码
 1 public interface Cache {
 2    .........
 3     void putObject(Object var1, Object var2);
 4    ..........
 5 }
 6 
 7 public class PerpetualCache implements Cache {
 8      .......
 9     public void putObject(Object key, Object value) {
10         this.cache.put(key, value);
11     }
12      .......
13 }
14 //在具体装饰类中对具体构件对象进行了功能扩充,在putObject方法中实现了先进先出策略。
15 public class FifoCache implements Cache {
16     private final Cache delegate;
17     private final Deque<Object> keyList;
18     private int size;
19     public FifoCache(Cache delegate) {
20         this.delegate = delegate;
21         this.keyList = new LinkedList();
22         this.size = 1024;
23     }
24     .........
25     public void putObject(Object key, Object value) {
26         this.cycleKeyList(key);
27         this.delegate.putObject(key, value);
28     }
29     .......
30     private void cycleKeyList(Object key) {
31         this.keyList.addLast(key);
32         if (this.keyList.size() > this.size) {
33             Object oldestKey = this.keyList.removeFirst();
34             this.delegate.removeObject(oldestKey);
35         }
36     }
37 }
复制代码

组合模式

组合模式解决的问题是在处理树状结构数据时,希望对单个对象和对象集合进行统一的处理,而不需要区分它们的类型。在实现解析Mapper XML文件功能,Mybatis中的SqlNode是使用组合模式实现的。SqlNode是一个抽象类,它有两个重要的子类:MixedSqlNode和TextSqlNode。MixedSqlNode代表一个混合类型的SqlNode,包含了多个SqlNode,它的作用是将多个SqlNode组合成一个整体,通过递归调用其子节点的apply方法来完成SQL语句的拼接。TextSqlNode代表一个文本类型的SqlNode,它可以包含一个动态的表达式,通过参数的替换来生成最终的SQL语句片段。在解析Mapper XML文件时,Mybatis会将每个SQL语句解析为一个SqlNode树,然后通过递归调用SqlNode的apply方法来遍历整个树,最终将所有的SqlNode组合成一个完整的SQL语句。

代理模式

在访问目标对象之前或之后可以执行额外的操作,例如权限控制、缓存、日志记录等,从而对目标对象的访问进行了控制和增强。在 MyBatis 中,每个 Mapper 接口都需要有一个对应的 Mapper 映射文件,用于描述 SQL 语句和接口方法的映射关系。在运行时,MyBatis 会根据接口定义创建一个代理对象,该代理对象实现了该接口的所有方法,并将方法转换为执行对应的 SQL 语句。这里的代理对象就是使用 JDK 动态代理生成的。

行为型

模板方法模式

模板方式模式定义一个操作的算法骨架,将一些步骤延迟到子类中实现,从而使子类可以在不改变算法骨架的情况下重新定义某些步骤。Executor 是 MyBatis 的核心接口之一,定义了数据库操作的基本方法,其类图如下:

BaseExecutor 类中的 query() 方法会先创建 CacheKey 对象,并根据 CacheKey 对象查找一级缓存,如果缓存命中则返回缓存中记录的结果对象,如果未命中则查询数据库得到结果集,之后将结果集映射成结果对象并保存到一级缓存中,同时返回结果对象。

doUpdate、doFlushStatements、doQuery 和 doQueryCursor 这几个方法就是交由子类来实现的,也就是说继承 BaseExecutor 的子类只需要实现这 4 个基本方法来完成数据库的相关操作即可。

BaseExecutor 的子类有 SimpleExecutor、ReuseExecutor、BatchExecutor类。

 

迭代器模式

迭代器模式提供一种方法来遍历集合对象中的元素,而不需要暴露集合的内部结构。DefaultCursor 实现了 Cursor 接口,而Cursor接口实现了Iterable接口,Iterable接口中有Iterator方法,DefaultCursor 类定义了一个成员变量 cursorIterator,其类型为 CursorIterator,并在iterator方法中进行返回。而CursorIterator是DefaultCursor 的一个内部类,实现了 JDK 中的 Iterator 接口。

posted @   rongqing2019  阅读(65)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
点击右上角即可分享
微信分享提示