【MyBatis】面试官:MyBatis中是如何使用设计模式的?

简介: 本篇文章了解一下MyBatis中运用到的设计模式,我们在实际的开发中很大程度上只是对设计模式留在一个理论的环节上,缺少实践,通过源码,我们可以学习一下这些设计模式的实践方式,有利于我们能够更深入的理解和使用设计模式。

【概要】

本篇文章了解一下MyBatis中运用到的设计模式,我们在实际的开发中很大程度上只是对设计模式留在一个理论的环节上,缺少实践,通过源码,我们可以学习一下这些设计模式的实践方式,有利于我们能够更深入的理解和使用设计模式。

  1. Builder模式
  2. 工厂模式
  3. 单例模式
  4. 代理模式
  5. 组合模式
  6. 模板模式
  7. 适配器模式
  8. 装饰模式
  9. 迭代器模型

1. 【Builder模式】

属于:创建类模式

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

Builder模式的定义是“将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 抽象工厂与建造者 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。

SqlSessionFactoryBuilder类

网络异常,图片无法展示
|

SqlSessionFactoryBuilder通过调用build中的XMLConfigBuilder构造器,将该Configuration对象作为参数构建一个SqlSessionFactory对象。

网络异常,图片无法展示
|

XMLConfigBuilder继续调用mapperElement下的XMLMapperBuilder构造器,而XMLMapperBuilder会调用XMLStatementBuilder。


2. 【工厂模式】

属于:创建类模式

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

  1. 通过SqlSessionFactoryBuilder产生出来的DefaultSqlSessionFactory。调用不同的openSession方法,生成产品SqlSession。

网络异常,图片无法展示
|

  1. 简单工厂LogFactory,针对不同的日志输出

网络异常,图片无法展示
|


3. 【单例模式】

属于:创建类模式

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

ErrorContext

ErrorContext.instance().resource("SQL Mapper Configuration");

网络异常,图片无法展示
|

LOCAL的静态实例变量使用了ThreadLocal修饰,也就是说它属于每个线程各自的数据,而在instance()方法中,先获取本线程的该实例,如果没有就创建该线程独有的ErrorContext。

public static ErrorContext instance() {
  return LOCAL.get();
}

4. 【代理模式】

属于:结构型模式

意图:为其他对象提供一种代理以控制对这个对象的访问。

MapperProxyFactory

代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。

代理模式包含如下角色:

  • Subject: 抽象主题角色
  • Proxy: 代理主题角色
  • RealSubject: 真实主题角色

网络异常,图片无法展示
|

经典的实现InvocationHandler接口

public class MapperProxy<T> implements InvocationHandler, Serializable {
    ...
    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
  this.sqlSession = sqlSession;
  this.mapperInterface = mapperInterface;
  this.methodCache = methodCache;
  @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  try {
    if (Object.class.equals(method.getDeclaringClass())) {
      return method.invoke(this, args);
    } else {
      return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
    }
  } catch (Throwable t) {
    throw ExceptionUtil.unwrapThrowable(t);
  }
}
}
...
@Override
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
  return mapperMethod.execute(sqlSession, args);
}

在实现原数据MetaObject,用到了JavassistProxyFactory反射工具类

网络异常,图片无法展示
|


5. 【组合模式】

属于:结构型模式

意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。 在使用组合模式中需要注意一点也是组合模式最关键的地方:叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。

动态SQL就是利用组合模式。


6. 【模板模式】

属于:行为型模式

意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

前面说到的Executor,提供固定的方法,用来实现大部分的sql

网络异常,图片无法展示
|


7. 【适配器模式】

属于:结构型模式

意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

Log,不同的日志框架

网络异常,图片无法展示
|


8. 装饰模式

属于:结构型模式

意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。

在mybatis中,缓存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久缓存实现,然后通过一系列的装饰器来对PerpetualCache永久缓存进行缓存策略等方便的控制。

网络异常,图片无法展示
|

接口类:

网络异常,图片无法展示
|

实现类:

网络异常,图片无法展示
|

装饰类:

网络异常,图片无法展示
|

在原先的实现上,做一层扩展,符合设计模式的,对外开放,对内关闭的原则, Cache对象之间的引用顺序为:SynchronizedCache–>LoggingCache–>SerializedCache–>ScheduledCache–>LruCache–>PerpetualCache

@Test
void shouldRemoveFirstItemInBeyondFiveEntries() {
  FifoCache cache = new FifoCache(new PerpetualCache("default"));
  cache.setSize(5);
  for (int i = 0; i < 5; i++) {
    cache.putObject(i, i);
  }
  assertEquals(0, cache.getObject(0));
  cache.putObject(5, 5);
  assertNull(cache.getObject(0));
  assertEquals(5, cache.getSize());
}

9. 【迭代器模型】

属于:行为型模式

意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。

实现iterator接口的就算是迭代器模型

myBatis中PropertyTokenizer就是使用迭代器模型

public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
  private String name;
  private final String indexedName;
  private String index;
  private final String children;
  public PropertyTokenizer(String fullname) {
    int delim = fullname.indexOf('.');
    if (delim > -1) {
      name = fullname.substring(0, delim);
      children = fullname.substring(delim + 1);
    } else {
      name = fullname;
      children = null;
    }
    indexedName = name;
    delim = name.indexOf('[');
    if (delim > -1) {
      index = name.substring(delim + 1, name.length() - 1);
      name = name.substring(0, delim);
    }
  }
  public String getName() {
    return name;
  }
  public String getIndex() {
    return index;
  }
  public String getIndexedName() {
    return indexedName;
  }
  public String getChildren() {
    return children;
  }
  @Override
  public boolean hasNext() {
    return children != null;
  }
  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children);
  }
  @Override
  public void remove() {
    throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
  }

相关文章
|
6月前
|
缓存 Java 数据库连接
Mybatis缓存相关面试题有多卷
使用 MyBatis 缓存机制需要注意以下几点: 对于频繁更新和变动的数据,不适合使用缓存。 对于数据的一致性要求比较高的场景,不适合使用缓存。 如果配置了二级缓存,需要确保缓存的数据不会影响到其他业务模块的数据。 在使用缓存时,需要注意缓存的命中率和缓存的过期策略,避免缓存过期导致查询性能下降。
105 0
|
1月前
|
设计模式 缓存 Java
面试题:谈谈Spring用到了哪些设计模式?
面试题:谈谈Spring用到了哪些设计模式?
|
5月前
|
SQL 缓存 Java
MyBatis最经典的20道面试题,你都会了吗?
MyBatis最经典的20道面试题,你都会了吗?
68 0
|
2月前
|
设计模式 安全 算法
【Java面试题汇总】设计模式篇(2023版)
谈谈你对设计模式的理解、七大原则、单例模式、工厂模式、代理模式、模板模式、观察者模式、JDK中用到的设计模式、Spring中用到的设计模式
【Java面试题汇总】设计模式篇(2023版)
|
3月前
|
设计模式 安全 图形学
Unity精华☀️ 面试官眼中的「设计模式」
Unity精华☀️ 面试官眼中的「设计模式」
|
6月前
|
SQL 缓存 Java
Mybatis面试题
Mybatis面试题
|
3月前
|
设计模式 算法 Java
面试官:JDK中都用了哪些设计模式?
面试官:JDK中都用了哪些设计模式?
42 0
|
4月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
78 1
|
4月前
|
设计模式 存储 缓存
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
56 0