【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.");
  }

相关文章
|
5月前
|
Java 关系型数据库 数据库连接
BATJ高频面试249道题:微服务+多线程+分布式+MyBatis +Spring
本文收集整理了各大厂常见面试题N道,你想要的这里都有内容涵盖:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等技术栈,希望大家都能找到适合自己的公司,开开心心的撸代码。
|
1月前
|
SQL 缓存 Java
Mybatis面试题
Mybatis面试题
|
8月前
|
缓存 Java 数据库连接
「Java面试」五年Java程序员去某东面试竟然在MyBatis缓存这翻车
一个5年工作经验的小伙伴,去面某东被问到MyBatis何时使用一级缓存,何时使用二级缓存?去之前还特地复习了MyBatis的相关知识,想着自己用MyBatis用得比较熟练了,竟然在这道题上翻车了。 今天,我给大家来分享一下MyBatis的缓存机制。
61 0
|
1月前
|
SQL Java 数据库连接
MyBatis常见面试题总结2
MyBatis常见面试题总结
23 0
|
1月前
|
SQL Java 数据库连接
MyBatis常见面试题总结1
MyBatis常见面试题总结
26 0
|
2月前
|
SQL Java 数据库连接
答案很详细的MyBatis面试题(含示例代码)
MyBatis是一种优秀的持久层框架,它是一个轻量级的、优化的、功能强大的Java持久层框架,它的设计理念是贴近SQL、便于使用、高效并且功能丰富。通过MyBatis的使用,开发者能够更加专注于业务逻辑的实现,而不用过多关注底层的数据库操作。MyBatis通过XML或注解的方式配置SQL映射文件,并将Java的POJO(Plain Old Java Object,普通的Java对象)与数据库中的记录进行映射,使得开发人员能够以面向对象的方式来操作数据库,同时兼顾了SQL的灵活性和效率。灵活的SQL映射。
120 0
|
2月前
|
存储 缓存 Java
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
什么!?实战项目竟然撞到阿里面试的原题!???关于MyBatis Plus的缓存机制
|
8月前
|
SQL Java 数据库连接
MyBatis进阶:掌握MyBatis动态SQL与模糊查询、结果映射,让你在面试中脱颖而出!!
MyBatis进阶:掌握MyBatis动态SQL与模糊查询、结果映射,让你在面试中脱颖而出!!
144 0
|
3月前
|
SQL Java 数据库连接
MyBatis常见面试题和答案(2020最新版)
MyBatis常见面试题和答案(2020最新版)
140 0
|
8月前
|
缓存 Java 数据库连接
面试官:说一下 MyBatis 缓存机制?
面试官:说一下 MyBatis 缓存机制?
190 2