MyBatis源码中的设计模式1

1. 建造者模式的应用

建造者模式属于创建类模式,通过一步一步地创建一个复杂的对象,能够将部件与其组装过程分开。用户只需指定复杂对象的类型,就可以得到该对象,而不需要了解其内部的具体构造细节。《Effective Java》中也提到,遇到多个构造器参数时,考虑用构建者(Builder)模式。

在 Mybatis 的环境初始化过程中,SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的MybatisMapConfig.xml和所有的*Mapper.xml文件,构建 Mybatis 运行的核心对象Configuration对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。

示例图

在这里插入图片描述

其中,XMLConfigBuilder在构建Configuration对象时,也会调用XMLMapperBuilder用于读取*.Mapper文件,而XMLMapperBuilder会使用XMLStatementBuilder来读取和构建所有的 SQL 语句。

示例图

在这里插入图片描述

在这个过程中,Builder模式会读取文件或者配置,然后做大量的 XPath 解析、配置或语法解析、反射生成对象、存入结果缓存等步骤。因此,大量采用了 Builder 模式来解决这些问题。

对于Builder的具体类,方法大都用build*开头,比如SqlSessionFactoryBuilder类中包含的方法:

示例图

在这里插入图片描述

从建造者模式的设计初衷来看,SqlSessionFactoryBuilder虽然带有 Builder 后缀,但不完全是标准的建造者模式。它的设计初衷是为了简化开发,隐藏构建SqlSessionFactory的复杂过程,对程序员透明。

2. 工厂模式的应用

在 Mybatis 中,SqlSessionFactory使用了简单工厂模式。

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。简单工厂模式中,可以根据参数的不同返回不同类的实例。

示例图

在这里插入图片描述

SqlSession是 Mybatis 工作的核心接口,通过这个接口可以执行 SQL 语句、获取 Mappers、管理事务。

示例图

在这里插入图片描述

DefaultSqlSessionFactory的默认工厂实现里,openSessionFromDataSource方法展示了工厂如何产出一个产品:

示例图

在这里插入图片描述

这个方法会先从configuration读取对应的环境配置,然后初始化TransactionFactory获得一个Transaction对象,通过Transaction获取一个Executor对象,最后通过configurationExecutorautoCommit参数构建了SqlSession

3. 代理模式的应用

代理模式是 Mybatis 核心使用的模式,使我们只需要编写Mapper.java接口,不需要实现,由 Mybatis 背后完成具体 SQL 的执行。

代理模式(Proxy Pattern):给某个对象提供一个代理,并由代理对象控制对原对象的引用。

示例图

在这里插入图片描述

每次调用sqlSessiongetMapper方法时,都会创建一个新的动态代理类实例。

示例图

在这里插入图片描述

当我们使用ConfigurationgetMapper方法时,会调用mapperRegistry.getMapper方法,

示例图

在这里插入图片描述

在这里,通过T newInstance(SqlSession sqlSession)方法得到一个MapperProxy对象,然后调用T newInstance(MapperProxy<T> mapperProxy)生成代理对象。

示例图

在这里插入图片描述

通过这种方式,我们只需要编写Mapper.java接口类,实际执行时会转发给MapperProxy.invoke方法,调用后续的sqlSession.cud > executor.execute > prepareStatement等方法,完成 SQL 的执行和返回。

4. 模板方法模式的应用

在 Mybatis 中,sqlSession的 SQL 执行委托给Executor实现,Executor包含以下结构:

示例图

在这里插入图片描述

其中的BaseExecutor采用了模板方法模式,实现了大部分的 SQL 执行逻辑,把几个方法交给子类定制化完成。

示例图

在这里插入图片描述

模板模式基于继承实现代码复用。抽象类中包含模板方法,调用有待子类实现的抽象方法。

5. 装饰者模式的应用

装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,比生成子类实现更为灵活。

在 Mybatis 中,缓存功能由根接口Cache定义,采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache实现,然后通过一系列的装饰器来对PerpetualCache进行缓存策略等方面的控制。

示例图

在这里插入图片描述

用于装饰PerpetualCache的标准装饰器有:

  1. FifoCache
  2. LoggingCache
  3. LruCache
  4. ScheduledCache
  5. SerializedCache
  6. SoftCache
  7. SynchronizedCache
  8. WeakCache

Mybatis 采用装饰器模式实现缓存功能,通过组合而非继承,更加灵活,避免了继承关系的组合爆炸。

6. 迭代器模式的应用

迭代器模式介绍

  • 迭代器模式是一个行为型设计模式,用于在不暴露其底层表示的情况下顺序访问集合对象的元素。在大多数编程语言中,迭代器已经成为基础的类库,直接用来遍历集合对象。在日常开发中,我们通常直接使用现有的迭代器,而不需要从零实现一个。
  • 在软件系统中,容器对象有两个职责:存储数据和遍历数据。从依赖性角度看,前者是聚合对象的基本职责,后者是可变化且可分离的。因此,可以将遍历数据的行为从容器中抽取出来,封装到迭代器对象中,由迭代器提供遍历数据的功能。这将简化聚合对象的设计,更加符合单一职责原则。

在这里插入图片描述

迭代器模式主要包含以下角色:

  1. 抽象集合(Aggregate)角色:用于存储和管理元素对象,定义存储、添加、删除集合元素的功能,并声明一个 createIterator() 方法用于创建迭代器对象。
  2. 具体集合(ConcreteAggregate)角色:实现抽象集合类,返回一个具体迭代器的实例。
  3. 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()next() 等方法。
    • hasNext() 方法用于判断集合中是否还有下一个元素。
    • next() 方法用于将游标后移一位元素。
    • currentItem() 方法用于返回当前游标指向的元素。
  4. 具体迭代器(ConcreteIterator)角色:实现抽象迭代器接口中定义的方法,完成对集合对象的遍历,同时记录遍历的当前位置。

在Java中,Iterator接口就是迭代器模式的实现,只要实现了该接口,就相当于应用了迭代器模式:

在这里插入图片描述

迭代器模式总结

使用场景

  1. 访问一个聚合对象的内容,不需要暴露它的内部表示。
  2. 支持对聚合对象的多种遍历。
  3. 迭代器模式与集合同时存在。

优点

  1. 支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。
  2. 迭代器简化了聚合类。引入迭代器模式后,聚合对象不再需要自行提供数据遍历访问的方法。
  3. 可以为不同的聚合结构提供一个统一的接口。

缺点

  1. 迭代器模式将存储数据和遍历数据的职责分离开,增加新的聚合类型需要增加对应的新迭代器类,增加了系统复杂性。

MyBatis中的应用

MyBatis的 PropertyTokenizer 是 property 包中的重要类,它实现了 Iterator 接口,并在 reflection 包中的其他类中被频繁引用。该类的 hasNext() 方法经常被使用。

/*** 属性分词器* * 实现 Iterator 接口,用于遍历属性的各个部分*/
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;}@Overridepublic boolean hasNext() {return children != null;}@Overridepublic PropertyTokenizer next() {return new PropertyTokenizer(children);}@Overridepublic void remove() {throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");}
}

这个类传入一个字符串到构造函数,然后提供了 iterator 方法对解析后的子串进行遍历,是一个非常常用的方法类。

PropertyTokenizer 类虽然实现了 Iterator 接口,但并非标准的迭代器类。它将配置解析、解析后的元素、迭代器这三部分本应分开的代码耦合在一起,因此略显复杂。不过,这样做的好处是能够实现惰性解析,不需要事先将整个配置解析成多个 PropertyTokenizer 对象,只有在调用 next() 方法时才会解析部分配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/47182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

捷配PCB打样采用机械盲埋孔制造,有何优势?

在电子制造领域&#xff0c;盲孔&#xff08;Blind Vias&#xff09;与埋孔&#xff08;Buried Vias&#xff09;是两种关键的PCB&#xff08;印刷电路板&#xff09;过孔技术。盲孔特指那些连接内层走线至外层走线的过孔&#xff0c;但并不贯穿整个板体。相对地&#xff0c;埋…

镜舟科技荣获优秀数字化服务商奖,助力企业用数智技术重塑新消费

7 月 13 日&#xff0c;由 ITShare智享会和 BT商业科技观察主办的2024 第八届 FMCG 零售消费品数字化峰会于上海落幕。在现场&#xff0c;镜舟科技凭借在多家零售企业构建与实施智能数据中台解决方案的成功经验&#xff0c;荣获优秀数字化服务商奖项。 在会上&#xff0c;麦当劳…

云动态摘要 2024-07-16

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 数据库上云优选 阿里云 2024-07-04 RDS、PolarDB、Redis、MongoDB 全系产品新用户低至首年6折起&#xff01; [免费体验]智能助手ChatBI上线 腾讯云 2024-07-02 基于混元大模型打造&…

C语言 ——— 编写代码,判断 整型数组 是否 有序

目录 题目要求 代码实现 题目要求 判断 整型数组 是否有序 如果 整型数组 有序输出 sorted&#xff1b;否则输出 unsorted 代码实现 #include<stdio.h> int main() {int arr[10] { 0 };int sz sizeof(arr) / sizeof(arr[0]);//输入for (int i 0; i < sz; i){s…

线程控制

对线程的控制思路和进程相似&#xff0c;创建、等待、终止&#xff0c;只需要调用接口就行。但是在Linux下没有线程的概念&#xff0c;因为Linux的设计者认为&#xff0c;线程是一种轻量级的进程&#xff0c;毕竟创建线程只需要创建PCB。因此Linux中使用多线程必须使用第三方pt…

Spring MVC入门2

Postman的使用 接上期我们抛出了一个问题&#xff0c;Postman的使用 可以点击链接下载 https://www.postman.com/downloads/ 安装之后会提示版本升级&#xff0c;直接点击dissmiss即可。 要想发送数据&#xff0c;具体歩奏如下简图&#xff1a; 还有一个更具体的图&#xff…

使用GDAL(C++库)从末尾行开始向上读取图像数据

使用GDAL&#xff08;C库&#xff09;从末尾行读取图像数据 OpenCV等图像库默认的读取方式都是从第一行开始&#xff0c;逐行读取数据&#xff08;自顶向下&#xff09;&#xff0c;填充到内存缓冲区&#xff1b;对于某些特殊应用&#xff0c;需要反行序读取&#xff08;从末尾…

朴素模式匹配算法与KMP算法(非重点)

目录 一. 朴素模式匹配算法1.1 什么是字符串的匹配模式1.2 朴素模式匹配算法1.3 通过数组下标实现朴素模式匹配算法 二. KMP算法2.1 算法分析2.2 用代码实现&#xff08;只会出现在选择题&#xff0c;考察代码的概率不大&#xff09; 三. 手算next数组四. KMP算法的进一步优化4…

在AWS创建一台Windows主机并登录

正文共&#xff1a;1111 字 21 图&#xff0c;预估阅读时间&#xff1a;1 分钟 因为之前微软云Azure免费&#xff0c;我们还做了简单的测试&#xff08;白嫖党618福利&#xff01;来Azure领200美刀&#xff01;外加云主机免费用一年&#xff01;&#xff09;&#xff1b;并且通…

k8s核心操作_存储抽象_K8S中使用Secret功能来存储密码_使用免密拉取镜像_k8s核心实战总结---分布式云原生部署架构搭建033

注意在看的时候一定要把 dxxxx中的xxxx换成--o----c----k----e----r 然后我们再来看一个k8s中的secret的功能,这个功能 用来存储密码的,configMap是用来存配置的 比如我们有个pod,他的镜像,如果是需要密码的,那么 我们现在是从公共仓库拉取的,如果我们从私有仓库拉取,有密码…

从 Icelake 到 Iceberg Rust

本文作者丁皓是Databend 研发工程师&#xff0c;也是 ASF Member&#xff0c; Apache OpenDAL PMC Chair &#xff0c;主要研究领域包括存储、自动化与开源。 太长不看 Icelake 已经停止更新&#xff0c;请改用 iceberg-rust。 Iceberg-rust 是一个由社区驱动的项目&#xff0…

《0基础》学习Python——第十六讲

《文件读写》 一、什么是文件读写 文件读写是指在Python程序中对文件进行读取和写入操作。通过文件读写&#xff0c;可以读取文件中的数据&#xff0c;或者向文件中写入数据。 Python提供了多种文件读写的方式&#xff0c;其中最常用的方式是使用open()函数打开一个文件&#…

深入理解Android中的缓存与文件存储目录

&#x1f31f; 引言 在Android应用开发中&#xff0c;合理管理应用的数据存储至关重要。应用可能需要保存各种类型的数据&#xff0c;从简单的配置信息到多媒体文件&#xff0c;甚至是缓存数据以提高性能和用户体验。Android提供了多个内置目录来满足这些需求&#xff0c;但它…

kubernetes集群环境搭建(二)

kubernetes集群类型 kubernetes集群大体上分为两类&#xff1a;一主多从和多主多从 一主多从&#xff1a;一台Master节点和多台Node节点&#xff0c;搭建简单&#xff0c;但有单机故障风险&#xff0c;适合于测试环境部署多主多从&#xff1a;多台Matser节点和多台Node节点&…

策略模式原理与C++实现

定义 定义一些列算法&#xff0c;把他们一个个封装起来&#xff0c;并且使他们可以相互替换&#xff08;变化&#xff09;。该模式使得算法可独立于使用它的客户程序&#xff08;稳定&#xff09;而变化&#xff08;扩展、子类化&#xff09;。 C实现 在不考虑策略模式的情况…

js基础-小数计算,并转换成带两位的百分比

小数计算&#xff0c;并转换成带两位的百分比 1、需求说明2、执行过程2.1 计算 s12.2 计算 s2 1、需求说明 在工作中&#xff0c;有时需要将计算的小数转换成百分比小数&#xff0c;但是在js代码中&#xff0c;计算公式一点点的区别就会影响到最终的结果&#xff0c;如下面代码…

vue视频、图片自动轮播并伴随进度条

废话不多说直接上代 多余没用的部分自己看着删除 <template><div class"showImg"><el-carousel ref"carousel" trigger"hover" :autoplay"false" class"dimControl" :height"${(currenInnerWith*0.37…

spring框架之AOP注解方式(java代码实例)

目录 半注解形式&#xff1a; 业务层接口实现类&#xff1a; 编写切面类&#xff1a; 在配置文件里面唯一需要加的&#xff1a; 测试类&#xff1a; 全注解形式&#xff1a; 不要配置文件&#xff0c;改为配置类&#xff1a; 同样的业务层接口实现类&#xff1a; 同样的…

2024年【天津市安全员C证】免费试题及天津市安全员C证考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 天津市安全员C证免费试题根据新天津市安全员C证考试大纲要求&#xff0c;安全生产模拟考试一点通将天津市安全员C证模拟考试试题进行汇编&#xff0c;组成一套天津市安全员C证全真模拟考试试题&#xff0c;学员可通过…

Java红娘婚恋相亲交友系统小程序源码

红娘婚恋相亲交友小程序&#xff1a;遇见爱情&#xff0c;从指尖开始&#x1f496; &#x1f4f1; 掌中红娘&#xff0c;随时待命 &#x1f48c; 在这个数字化时代&#xff0c;爱情也迎来了它的新舞台——“红娘婚恋相亲交友小程序”。只需轻轻一点&#xff0c;你的专属红娘就…